summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt31
-rw-r--r--core/java/android/app/ActivityManager.java7
-rw-r--r--core/java/android/app/ActivityManagerNative.java2
-rw-r--r--core/java/android/app/ContextImpl.java5
-rw-r--r--core/java/android/content/ContentProvider.java59
-rw-r--r--core/java/android/content/ContentProviderClient.java5
-rw-r--r--core/java/android/content/ContentResolver.java3
-rw-r--r--core/java/android/database/MatrixCursor.java4
-rw-r--r--core/java/android/preference/PreferenceActivity.java7
-rw-r--r--core/java/android/printservice/PrintService.java6
-rw-r--r--core/java/android/printservice/PrintServiceInfo.java8
-rw-r--r--core/java/android/provider/DocumentsContract.java13
-rw-r--r--core/java/android/speech/hotword/HotwordRecognitionService.java40
-rw-r--r--core/java/android/speech/hotword/HotwordRecognizer.java45
-rw-r--r--core/java/android/transition/TextChange.java4
-rw-r--r--core/java/android/view/InputDevice.java13
-rw-r--r--core/java/android/view/View.java15
-rw-r--r--core/java/android/view/ViewDebug.java39
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java34
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java44
-rw-r--r--core/java/android/view/accessibility/CaptioningManager.java8
-rw-r--r--core/java/android/widget/AbsListView.java16
-rw-r--r--core/java/android/widget/FastScroller.java95
-rw-r--r--core/java/android/widget/VideoView.java162
-rw-r--r--core/java/com/android/internal/app/ProcessStats.java261
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java10
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuPresenter.java23
-rw-r--r--core/java/com/android/internal/widget/AutoScrollHelper.java4
-rw-r--r--core/java/com/android/internal/widget/SubtitleView.java4
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp8
-rw-r--r--core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp125
-rw-r--r--core/jni/android/graphics/Graphics.cpp43
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h11
-rw-r--r--core/res/res/drawable-nodpi/view_accessibility_focused.9.pngbin862 -> 0 bytes
-rw-r--r--core/res/res/drawable/view_accessibility_focused.xml25
-rw-r--r--core/res/res/values-af/strings.xml4
-rw-r--r--core/res/res/values-am/strings.xml18
-rw-r--r--core/res/res/values-ar/strings.xml2
-rw-r--r--core/res/res/values-az-rAZ/strings.xml2
-rw-r--r--core/res/res/values-be/strings.xml4
-rw-r--r--core/res/res/values-bg/strings.xml4
-rw-r--r--core/res/res/values-ca/strings.xml18
-rw-r--r--core/res/res/values-cs/strings.xml4
-rw-r--r--core/res/res/values-da/strings.xml4
-rw-r--r--core/res/res/values-de/strings.xml4
-rw-r--r--core/res/res/values-el/strings.xml4
-rw-r--r--core/res/res/values-en-rGB/strings.xml4
-rw-r--r--core/res/res/values-en-rIN/strings.xml4
-rw-r--r--core/res/res/values-es-rUS/strings.xml6
-rw-r--r--core/res/res/values-es/strings.xml8
-rw-r--r--core/res/res/values-et-rEE/strings.xml4
-rw-r--r--core/res/res/values-fa/strings.xml4
-rw-r--r--core/res/res/values-fi/strings.xml4
-rw-r--r--core/res/res/values-fr-rCA/strings.xml8
-rw-r--r--core/res/res/values-fr/strings.xml8
-rw-r--r--core/res/res/values-hi/strings.xml56
-rw-r--r--core/res/res/values-hr/strings.xml4
-rw-r--r--core/res/res/values-hu/strings.xml4
-rw-r--r--core/res/res/values-hy-rAM/strings.xml4
-rw-r--r--core/res/res/values-in/strings.xml4
-rw-r--r--core/res/res/values-it/strings.xml4
-rw-r--r--core/res/res/values-iw/strings.xml2
-rw-r--r--core/res/res/values-ja/strings.xml4
-rw-r--r--core/res/res/values-ka-rGE/strings.xml6
-rw-r--r--core/res/res/values-km-rKH/strings.xml2
-rw-r--r--core/res/res/values-ko/strings.xml4
-rw-r--r--core/res/res/values-lo-rLA/strings.xml4
-rw-r--r--core/res/res/values-lt/strings.xml4
-rw-r--r--core/res/res/values-lv/strings.xml4
-rw-r--r--core/res/res/values-mn-rMN/strings.xml2
-rw-r--r--core/res/res/values-ms-rMY/strings.xml8
-rw-r--r--core/res/res/values-nb/strings.xml4
-rw-r--r--core/res/res/values-ne-rNP/strings.xml12
-rw-r--r--core/res/res/values-nl/strings.xml4
-rw-r--r--core/res/res/values-pl/strings.xml4
-rw-r--r--core/res/res/values-pt-rPT/strings.xml4
-rw-r--r--core/res/res/values-pt/strings.xml4
-rw-r--r--core/res/res/values-rm/strings.xml4
-rw-r--r--core/res/res/values-ro/strings.xml4
-rw-r--r--core/res/res/values-ru/strings.xml4
-rw-r--r--core/res/res/values-si-rLK/strings.xml6
-rw-r--r--core/res/res/values-sk/strings.xml8
-rw-r--r--core/res/res/values-sl/strings.xml4
-rw-r--r--core/res/res/values-sr/strings.xml4
-rw-r--r--core/res/res/values-sv/strings.xml4
-rw-r--r--core/res/res/values-sw/strings.xml4
-rw-r--r--core/res/res/values-th/strings.xml4
-rw-r--r--core/res/res/values-tl/strings.xml4
-rw-r--r--core/res/res/values-tr/strings.xml4
-rw-r--r--core/res/res/values-uk/strings.xml8
-rw-r--r--core/res/res/values-vi/strings.xml4
-rw-r--r--core/res/res/values-zh-rCN/strings.xml4
-rw-r--r--core/res/res/values-zh-rHK/strings.xml4
-rw-r--r--core/res/res/values-zh-rTW/strings.xml4
-rw-r--r--core/res/res/values-zu/strings.xml2
-rw-r--r--core/res/res/values/attrs.xml4
-rw-r--r--core/res/res/values/colors.xml2
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/tests/ConnectivityManagerTest/AndroidManifest.xml3
-rw-r--r--core/tests/coretests/src/android/database/MatrixCursorTest.java16
-rw-r--r--docs/html/training/id-auth/authenticate.jd2
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java41
-rw-r--r--graphics/java/android/graphics/PixelFormat.java19
-rw-r--r--graphics/jni/android_renderscript_RenderScript.cpp2
-rw-r--r--libs/hwui/FontRenderer.cpp2
-rw-r--r--media/java/android/media/SubtitleController.java26
-rw-r--r--media/java/android/media/SubtitleTrack.java77
-rw-r--r--media/java/android/media/WebVttRenderer.java810
-rw-r--r--packages/DocumentsUI/res/drawable/item_background.xml24
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java259
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java85
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java164
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java119
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java12
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java30
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java42
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java172
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java117
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java28
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java128
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java2
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java26
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java29
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java13
-rw-r--r--packages/SystemUI/res/drawable-nodpi/lightning.pngbin2896 -> 0 bytes
-rw-r--r--packages/SystemUI/res/values/arrays.xml11
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/BatteryMeterView.java113
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java30
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java24
-rw-r--r--services/java/com/android/server/am/ActivityStack.java6
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java77
-rw-r--r--services/java/com/android/server/am/ProcessStatsService.java6
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java1
-rw-r--r--services/java/com/android/server/print/PrintManagerService.java23
-rw-r--r--services/java/com/android/server/print/RemotePrintService.java14
-rw-r--r--services/java/com/android/server/print/RemotePrintSpooler.java25
-rw-r--r--services/java/com/android/server/print/UserState.java102
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java11
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java91
142 files changed, 3312 insertions, 1012 deletions
diff --git a/api/current.txt b/api/current.txt
index c7b3ed9..b8caad8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -289,14 +289,14 @@ package android {
field public static final deprecated int animationResolution = 16843546; // 0x101031a
field public static final int antialias = 16843034; // 0x101011a
field public static final int anyDensity = 16843372; // 0x101026c
- field public static final int apduServiceBanner = 16843758; // 0x10103ee
+ field public static final int apduServiceBanner = 16843757; // 0x10103ed
field public static final int apiKey = 16843281; // 0x1010211
field public static final int author = 16843444; // 0x10102b4
field public static final int authorities = 16842776; // 0x1010018
field public static final int autoAdvanceViewId = 16843535; // 0x101030f
field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
field public static final int autoLink = 16842928; // 0x10100b0
- field public static final int autoMirrored = 16843755; // 0x10103eb
+ field public static final int autoMirrored = 16843754; // 0x10103ea
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -393,7 +393,6 @@ package android {
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
field public static final int customNavigationLayout = 16843474; // 0x10102d2
- field public static final int customRoots = 16843754; // 0x10103ea
field public static final int customTokens = 16843579; // 0x101033b
field public static final int cycles = 16843220; // 0x10101d4
field public static final int dashGap = 16843175; // 0x10101a7
@@ -846,7 +845,7 @@ package android {
field public static final int prompt = 16843131; // 0x101017b
field public static final int propertyName = 16843489; // 0x10102e1
field public static final int protectionLevel = 16842761; // 0x1010009
- field public static final int provideAssistData = 16843759; // 0x10103ef
+ field public static final int provideAssistData = 16843758; // 0x10103ee
field public static final int publicKey = 16843686; // 0x10103a6
field public static final int queryActionMsg = 16843227; // 0x10101db
field public static final int queryAfterZeroResults = 16843394; // 0x1010282
@@ -871,7 +870,7 @@ package android {
field public static final int reqKeyboardType = 16843304; // 0x1010228
field public static final int reqNavigation = 16843306; // 0x101022a
field public static final int reqTouchScreen = 16843303; // 0x1010227
- field public static final int requireDeviceUnlock = 16843757; // 0x10103ed
+ field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
@@ -1020,7 +1019,7 @@ package android {
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsRtl = 16843695; // 0x10103af
- field public static final int supportsSwitchingToNextInputMethod = 16843756; // 0x10103ec
+ field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
field public static final int supportsUploading = 16843419; // 0x101029b
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
@@ -8140,7 +8139,7 @@ package android.database {
public class MatrixCursor.RowBuilder {
method public android.database.MatrixCursor.RowBuilder add(java.lang.Object);
- method public android.database.MatrixCursor.RowBuilder offer(java.lang.String, java.lang.Object);
+ method public android.database.MatrixCursor.RowBuilder add(java.lang.String, java.lang.Object);
}
public class MergeCursor extends android.database.AbstractCursor {
@@ -20774,7 +20773,6 @@ package android.provider {
method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildRootsUri(java.lang.String);
method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
- method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
method public static java.lang.String getDocumentId(android.net.Uri);
method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal);
@@ -20796,6 +20794,7 @@ package android.provider {
field public static final java.lang.String COLUMN_SIZE = "_size";
field public static final java.lang.String COLUMN_SUMMARY = "summary";
field public static final int FLAG_DIR_PREFERS_GRID = 32; // 0x20
+ field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 64; // 0x40
field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
field public static final int FLAG_DIR_SUPPORTS_SEARCH = 16; // 0x10
field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
@@ -22818,6 +22817,15 @@ package android.speech.hotword {
method public android.os.IBinder onBind(android.content.Intent);
method public abstract void onStartHotwordRecognition(android.speech.hotword.HotwordRecognitionService.Callback);
method public abstract void onStopHotwordRecognition();
+ field public static final int ERROR_AUDIO = 1; // 0x1
+ field public static final int ERROR_CLIENT = 4; // 0x4
+ field public static final int ERROR_FAILED = 3; // 0x3
+ field public static final int ERROR_RECOGNIZER_BUSY = 2; // 0x2
+ field public static final int ERROR_SERVICE_ALREADY_STARTED = 6; // 0x6
+ field public static final int ERROR_TIMEOUT = 5; // 0x5
+ field public static final int ERROR_UNAVAILABLE = 7; // 0x7
+ field public static final int EVENT_TYPE_PROMPT_CHANGED = 1; // 0x1
+ field public static final java.lang.String KEY_PROMPT_TEXT = "prompt_text";
field public static final java.lang.String SERVICE_INTERFACE = "android.speech.hotword.HotwordRecognitionService";
}
@@ -28371,6 +28379,7 @@ package android.view {
method public android.view.ViewPropertyAnimator setInterpolator(android.animation.TimeInterpolator);
method public android.view.ViewPropertyAnimator setListener(android.animation.Animator.AnimatorListener);
method public android.view.ViewPropertyAnimator setStartDelay(long);
+ method public android.view.ViewPropertyAnimator setUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
method public void start();
method public android.view.ViewPropertyAnimator translationX(float);
method public android.view.ViewPropertyAnimator translationXBy(float);
@@ -29052,12 +29061,12 @@ package android.view.accessibility {
}
public class CaptioningManager {
- method public void addCaptioningStateChangeListener(android.view.accessibility.CaptioningManager.CaptioningChangeListener);
+ method public void addCaptioningChangeListener(android.view.accessibility.CaptioningManager.CaptioningChangeListener);
method public final float getFontScale();
method public final java.util.Locale getLocale();
method public android.view.accessibility.CaptioningManager.CaptionStyle getUserStyle();
method public final boolean isEnabled();
- method public void removeCaptioningStateChangeListener(android.view.accessibility.CaptioningManager.CaptioningChangeListener);
+ method public void removeCaptioningChangeListener(android.view.accessibility.CaptioningManager.CaptioningChangeListener);
}
public static final class CaptioningManager.CaptionStyle {
@@ -29071,7 +29080,7 @@ package android.view.accessibility {
field public final int foregroundColor;
}
- public abstract class CaptioningManager.CaptioningChangeListener {
+ public static abstract class CaptioningManager.CaptioningChangeListener {
ctor public CaptioningManager.CaptioningChangeListener();
method public void onEnabledChanged(boolean);
method public void onFontScaleChanged(float);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7c40bb1..2d28280 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2106,7 +2106,12 @@ public class ActivityManager {
}
// If the target is not exported, then nobody else can get to it.
if (!exported) {
- Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid);
+ /*
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
+ here);
+ */
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6d72114..653559d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -3377,7 +3377,7 @@ class ActivityManagerProxy implements IActivityManager
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(packageName);
- data.writeStrongBinder(observer.asBinder());
+ data.writeStrongBinder((observer != null) ? observer.asBinder() : null);
data.writeInt(userId);
mRemote.transact(CLEAR_APP_DATA_TRANSACTION, data, reply, 0);
reply.readException();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index e776a98..7ff7562 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1827,6 +1827,11 @@ class ContextImpl extends Context {
message);
}
+ /**
+ * Logs a warning if the system process directly called a method such as
+ * {@link #startService(Intent)} instead of {@link #startServiceAsUser(Intent, UserHandle)}.
+ * The "AsUser" variants allow us to properly enforce the user's restrictions.
+ */
private void warnIfCallingFromSystemProcess() {
if (Process.myUid() == Process.SYSTEM_UID) {
Slog.w(TAG, "Calling a method in the system process without a qualified user: "
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 65a3a07..3438419 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -34,7 +34,6 @@ import android.os.ICancellationSignal;
import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
@@ -196,13 +195,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -216,11 +215,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues);
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.insert(uri, initialValues);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -229,11 +228,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.bulkInsert(uri, initialValues);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -256,11 +255,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
}
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.applyBatch(operations);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -269,11 +268,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.delete(uri, selection, selectionArgs);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -283,11 +282,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.update(uri, values, selection, selectionArgs);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -296,12 +295,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openFile(
uri, mode, CancellationSignal.fromTransport(cancellationSignal));
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -310,22 +309,22 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openAssetFile(
uri, mode, CancellationSignal.fromTransport(cancellationSignal));
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@Override
public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.call(method, arg, extras);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -338,12 +337,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, "r");
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openTypedAssetFile(
uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -357,11 +356,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.canonicalize(uri);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -370,11 +369,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
}
- mCallingPackage.set(callingPkg);
+ final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.uncanonicalize(uri);
} finally {
- mCallingPackage.set(null);
+ setCallingPackage(original);
}
}
@@ -540,6 +539,16 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
/**
+ * Set the calling package, returning the current value (or {@code null})
+ * which can be used later to restore the previous state.
+ */
+ private String setCallingPackage(String callingPackage) {
+ final String original = mCallingPackage.get();
+ mCallingPackage.set(callingPackage);
+ return original;
+ }
+
+ /**
* Return the package name of the caller that initiated the request being
* processed on the current thread. The returned package will have been
* verified to belong to the calling UID. Returns {@code null} if not
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index e6d9b24..e83c727 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -344,7 +344,10 @@ public class ContentProviderClient {
/** {@hide} */
public static void closeQuietly(ContentProviderClient client) {
if (client != null) {
- client.release();
+ try {
+ client.release();
+ } catch (Exception ignored) {
+ }
}
}
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9f462aa..e914604 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1745,6 +1745,9 @@ public abstract class ContentResolver {
* @param extras any extras to pass to the SyncAdapter.
*/
public static void requestSync(Account account, String authority, Bundle extras) {
+ if (extras == null) {
+ throw new IllegalArgumentException("Must specify extras.");
+ }
SyncRequest request =
new SyncRequest.Builder()
.setSyncAdapter(account, authority)
diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java
index 2a0d9b9..5e107f2 100644
--- a/core/java/android/database/MatrixCursor.java
+++ b/core/java/android/database/MatrixCursor.java
@@ -186,7 +186,7 @@ public class MatrixCursor extends AbstractCursor {
* column value at a time. This follows the same ordering as the column
* names specified at cursor construction time.
* <li>Column and value pairs can be offered for possible inclusion using
- * {@link #offer(String, Object)}. If the cursor includes the given column,
+ * {@link #add(String, Object)}. If the cursor includes the given column,
* the value will be set for that column, otherwise the value is ignored.
* This approach is useful when matching data to a custom projection.
* </ul>
@@ -227,7 +227,7 @@ public class MatrixCursor extends AbstractCursor {
*
* @return this builder to support chaining
*/
- public RowBuilder offer(String columnName, Object value) {
+ public RowBuilder add(String columnName, Object value) {
for (int i = 0; i < columnNames.length; i++) {
if (columnName.equals(columnNames[i])) {
data[(row * columnCount) + i] = value;
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 5d886a3..a99705b 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -894,14 +894,11 @@ public abstract class PreferenceActivity extends ListActivity implements
*/
protected boolean isValidFragment(String fragmentName) {
if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.KITKAT) {
- Log.w(TAG, "Subclasses of PreferenceActivity must override isValidFragment(String)"
+ throw new RuntimeException(
+ "Subclasses of PreferenceActivity must override isValidFragment(String)"
+ " to verify that the Fragment class is valid! " + this.getClass().getName()
+ " has not checked if fragment " + fragmentName + " is valid.");
- // Return true for now, but will eventually return false when all bundled apps
- // have been modified. TODO: change to return false
- return true;
} else {
- Log.i(TAG, "PreferenceActivity built on pre-KLP launching fragment: " + fragmentName);
return true;
}
}
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 96552af..0ffc40a 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -20,6 +20,7 @@ import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -155,6 +156,8 @@ public abstract class PrintService extends Service {
private static final String LOG_TAG = "PrintService";
+ private static final boolean DEBUG = false;
+
/**
* The {@link Intent} action that must be declared as handled by a service
* in its manifest for the system to recognize it as a print service.
@@ -433,6 +436,9 @@ public abstract class PrintService extends Service {
case MSG_ON_PRINTJOB_QUEUED: {
PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Queued: " + printJobInfo);
+ }
onPrintJobQueued(new PrintJob(printJobInfo, mClient));
} break;
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 128628d..8e9636c 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -239,10 +239,10 @@ public final class PrintServiceInfo implements Parcelable {
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PrintServiceInfo{");
- builder.append("id:").append(mId).append(", ");
- builder.append("resolveInfo:").append(mResolveInfo).append(", ");
- builder.append("settingsActivityName:").append(mSettingsActivityName);
- builder.append("addPrintersActivityName:").append(mAddPrintersActivityName);
+ builder.append("id=").append(mId);
+ builder.append(", resolveInfo=").append(mResolveInfo);
+ builder.append(", settingsActivityName=").append(mSettingsActivityName);
+ builder.append(", addPrintersActivityName=").append(mAddPrintersActivityName);
builder.append("}");
return builder.toString();
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 5333a25..91b3b48 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -251,6 +251,15 @@ public final class DocumentsContract {
* @see #COLUMN_FLAGS
*/
public static final int FLAG_DIR_PREFERS_GRID = 1 << 5;
+
+ /**
+ * Flag indicating that a directory prefers its contents be sorted by
+ * {@link #COLUMN_LAST_MODIFIED}. Only valid when
+ * {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
+ *
+ * @see #COLUMN_FLAGS
+ */
+ public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 6;
}
/**
@@ -292,9 +301,6 @@ public final class DocumentsContract {
* @see #FLAG_LOCAL_ONLY
* @see #FLAG_SUPPORTS_CREATE
* @see #FLAG_ADVANCED
- * @see #FLAG_PROVIDES_AUDIO
- * @see #FLAG_PROVIDES_IMAGES
- * @see #FLAG_PROVIDES_VIDEO
*/
public static final String COLUMN_FLAGS = "flags";
@@ -688,6 +694,7 @@ public final class DocumentsContract {
* @param mimeType MIME type of new document
* @param displayName name of new document
* @return newly created document, or {@code null} if failed
+ * @hide
*/
public static Uri createDocument(ContentResolver resolver, Uri parentDocumentUri,
String mimeType, String displayName) {
diff --git a/core/java/android/speech/hotword/HotwordRecognitionService.java b/core/java/android/speech/hotword/HotwordRecognitionService.java
index 7a26e0c..1cba281 100644
--- a/core/java/android/speech/hotword/HotwordRecognitionService.java
+++ b/core/java/android/speech/hotword/HotwordRecognitionService.java
@@ -47,6 +47,38 @@ public abstract class HotwordRecognitionService extends Service {
/** Debugging flag */
private static final boolean DBG = false;
+ /**
+ * Key used to retrieve a string to be displayed to the user.
+ */
+ public static final String KEY_PROMPT_TEXT = "prompt_text";
+
+ /**
+ * Event type used to indicate to the user that the prompt for
+ * hotword recognition has changed.
+ */
+ public static final int EVENT_TYPE_PROMPT_CHANGED = 1;
+
+ /** Audio recording error. */
+ public static final int ERROR_AUDIO = 1;
+
+ /** RecognitionService busy. */
+ public static final int ERROR_RECOGNIZER_BUSY = 2;
+
+ /** This indicates a permanent failure and the clients shouldn't retry on this */
+ public static final int ERROR_FAILED = 3;
+
+ /** Client-side errors */
+ public static final int ERROR_CLIENT = 4;
+
+ /** The service timed out */
+ public static final int ERROR_TIMEOUT = 5;
+
+ /** The service received concurrent start calls */
+ public static final int ERROR_SERVICE_ALREADY_STARTED = 6;
+
+ /** Hotword recognition is unavailable on the device */
+ public static final int ERROR_UNAVAILABLE = 7;
+
private static final int MSG_START_RECOGNITION = 1;
private static final int MSG_STOP_RECOGNITION = 2;
@@ -94,7 +126,7 @@ public abstract class HotwordRecognitionService extends Service {
HotwordRecognitionService.this.onStartHotwordRecognition(mCurrentCallback);
} else {
try {
- listener.onHotwordError(HotwordRecognizer.ERROR_RECOGNIZER_BUSY);
+ listener.onHotwordError(ERROR_RECOGNIZER_BUSY);
} catch (RemoteException e) {
if (DBG) Log.d(TAG, "onError call from startRecognition failed");
}
@@ -105,10 +137,10 @@ public abstract class HotwordRecognitionService extends Service {
private void dispatchStopRecognition(IHotwordRecognitionListener listener) {
try {
if (mCurrentCallback == null) {
- listener.onHotwordError(HotwordRecognizer.ERROR_CLIENT);
+ listener.onHotwordError(ERROR_CLIENT);
Log.w(TAG, "stopRecognition called with no preceding startRecognition - ignoring");
} else if (mCurrentCallback.mListener.asBinder() != listener.asBinder()) {
- listener.onHotwordError(HotwordRecognizer.ERROR_RECOGNIZER_BUSY);
+ listener.onHotwordError(ERROR_RECOGNIZER_BUSY);
Log.w(TAG, "stopRecognition called by a different caller - ignoring");
} else { // the correct state
mCurrentCallback.onHotwordRecognitionStopped();
@@ -192,7 +224,7 @@ public abstract class HotwordRecognitionService extends Service {
}
try {
Log.e(TAG, "Recognition service called without HOTWORD_RECOGNITION permissions");
- listener.onHotwordError(HotwordRecognizer.ERROR_FAILED);
+ listener.onHotwordError(ERROR_FAILED);
} catch (RemoteException e) {
Log.e(TAG, "onHotwordError(ERROR_FAILED) message failed", e);
}
diff --git a/core/java/android/speech/hotword/HotwordRecognizer.java b/core/java/android/speech/hotword/HotwordRecognizer.java
index 939c11d..9f05f31 100644
--- a/core/java/android/speech/hotword/HotwordRecognizer.java
+++ b/core/java/android/speech/hotword/HotwordRecognizer.java
@@ -50,39 +50,6 @@ public class HotwordRecognizer {
/** Log messages identifier */
private static final String TAG = "HotwordRecognizer";
- /**
- * Key used to retrieve a string to be displayed to the user passed to the
- * {@link android.speech.hotword.HotwordRecognitionListener#onHotwordEvent(int, Bundle)} method.
- */
- public static final String PROMPT_TEXT = "prompt_text";
-
- /**
- * Event type used to indicate to the user that the hotword service has changed
- * its state.
- */
- public static final int EVENT_TYPE_STATE_CHANGED = 1;
-
- /** Audio recording error. */
- public static final int ERROR_AUDIO = 1;
-
- /** RecognitionService busy. */
- public static final int ERROR_RECOGNIZER_BUSY = 2;
-
- /** This indicates a permanent failure and the clients shouldn't retry on this */
- public static final int ERROR_FAILED = 3;
-
- /** Client-side errors */
- public static final int ERROR_CLIENT = 4;
-
- /** The service timed out */
- public static final int ERROR_TIMEOUT = 5;
-
- /** The service received concurrent start calls */
- public static final int ERROR_SERVICE_ALREADY_STARTED = 6;
-
- /** Hotword recognition is unavailable on the device */
- public static final int ERROR_UNAVAILABLE = 7;
-
/** action codes */
private static final int MSG_START = 1;
private static final int MSG_STOP = 2;
@@ -209,7 +176,7 @@ public class HotwordRecognizer {
if (mServiceComponent == null) {
Log.e(TAG, "no selected voice recognition service");
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
return;
} else {
serviceIntent.setComponent(mServiceComponent);
@@ -219,12 +186,12 @@ public class HotwordRecognizer {
Log.e(TAG, "bind to recognition service failed");
mConnection = null;
mService = null;
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
return;
}
putMessage(Message.obtain(mHandler, MSG_START));
} else {
- mListener.onHotwordError(ERROR_SERVICE_ALREADY_STARTED);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_SERVICE_ALREADY_STARTED);
return;
}
}
@@ -252,7 +219,7 @@ public class HotwordRecognizer {
if (DBG) Log.d(TAG, "service startRecognition command succeeded");
} catch (final RemoteException e) {
Log.e(TAG, "startRecognition() failed", e);
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
}
}
@@ -268,7 +235,7 @@ public class HotwordRecognizer {
if (DBG) Log.d(TAG, "service stopRecognition command succeeded");
} catch (final RemoteException e) {
Log.e(TAG, "stopRecognition() failed", e);
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
} finally {
mPendingTasks.clear();
mService = null;
@@ -281,7 +248,7 @@ public class HotwordRecognizer {
if (mService != null) {
return true;
}
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
Log.e(TAG, "not connected to the recognition service");
return false;
}
diff --git a/core/java/android/transition/TextChange.java b/core/java/android/transition/TextChange.java
index 1b26942..4f14d46 100644
--- a/core/java/android/transition/TextChange.java
+++ b/core/java/android/transition/TextChange.java
@@ -143,8 +143,8 @@ public class TextChange extends Transition {
final TextView view = (TextView) endValues.view;
Map<String, Object> startVals = startValues.values;
Map<String, Object> endVals = endValues.values;
- final String startText = (String) startVals.get(PROPNAME_TEXT);
- final String endText = (String) endVals.get(PROPNAME_TEXT);
+ final CharSequence startText = (CharSequence) startVals.get(PROPNAME_TEXT);
+ final CharSequence endText = (CharSequence) endVals.get(PROPNAME_TEXT);
if (!startText.equals(endText)) {
view.setText(startText);
Animator anim;
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index afc7b3e..e829116 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -424,12 +424,17 @@ public final class InputDevice implements Parcelable {
/**
* The controller number for a given input device.
* <p>
- * Each game controller or joystick is given a unique controller number when initially
- * configured by the system. The number is not stable and may be changed by the system at any
- * point. All controller numbers will be non-negative. A game controller or joystick will be
- * given a unique number indexed from one; everything else will be assigned a controller number
+ * Each gamepad or joystick is given a unique, positive controller number when initially
+ * configured by the system. This number may change due to events such as device disconnects /
+ * reconnects or user initiated reassignment. Any change in number will trigger an event that
+ * can be observed by registering an {@link InputManager.InputDeviceListener}.
+ * </p>
+ * <p>
+ * All input devices which are not gamepads or joysticks will be assigned a controller number
* of 0.
* </p>
+ *
+ * @return The controller number of the device.
*/
public int getControllerNumber() {
return mControllerNumber;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8616aba..30531ed 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9546,9 +9546,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setPivotX(float pivotX) {
ensureTransformationInfo();
- mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
final TransformationInfo info = mTransformationInfo;
- if (info.mPivotX != pivotX) {
+ boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
+ PFLAG_PIVOT_EXPLICITLY_SET;
+ if (info.mPivotX != pivotX || !pivotSet) {
+ mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
invalidateViewProperty(true, false);
info.mPivotX = pivotX;
info.mMatrixDirty = true;
@@ -9596,9 +9598,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setPivotY(float pivotY) {
ensureTransformationInfo();
- mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
final TransformationInfo info = mTransformationInfo;
- if (info.mPivotY != pivotY) {
+ boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
+ PFLAG_PIVOT_EXPLICITLY_SET;
+ if (info.mPivotY != pivotY || !pivotSet) {
+ mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
invalidateViewProperty(true, false);
info.mPivotY = pivotY;
info.mMatrixDirty = true;
@@ -13476,6 +13480,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
dispatchDraw(canvas);
+ if (mOverlay != null && !mOverlay.isEmpty()) {
+ mOverlay.getOverlayView().draw(canvas);
+ }
} else {
draw(canvas);
}
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index ed128b0..92e5e96 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -698,6 +698,11 @@ public class ViewDebug {
captureViewLayer(group.getChildAt(i), clientStream, localVisible);
}
}
+
+ if (view.mOverlay != null) {
+ ViewGroup overlayContainer = view.getOverlay().mOverlayViewGroup;
+ captureViewLayer(overlayContainer, clientStream, localVisible);
+ }
}
private static void outputDisplayList(View root, String parameter) throws IOException {
@@ -743,7 +748,7 @@ public class ViewDebug {
}
}
- private static Bitmap performViewCapture(final View captureView, final boolean skpiChildren) {
+ private static Bitmap performViewCapture(final View captureView, final boolean skipChildren) {
if (captureView != null) {
final CountDownLatch latch = new CountDownLatch(1);
final Bitmap[] cache = new Bitmap[1];
@@ -752,7 +757,7 @@ public class ViewDebug {
public void run() {
try {
cache[0] = captureView.createSnapshot(
- Bitmap.Config.ARGB_8888, 0, skpiChildren);
+ Bitmap.Config.ARGB_8888, 0, skipChildren);
} catch (OutOfMemoryError e) {
Log.w("View", "Out of memory for bitmap");
} finally {
@@ -815,6 +820,13 @@ public class ViewDebug {
} else if (isRequestedView(view, className, hashCode)) {
return view;
}
+ if (view.mOverlay != null) {
+ final View found = findView((ViewGroup) view.mOverlay.mOverlayViewGroup,
+ className, hashCode);
+ if (found != null) {
+ return found;
+ }
+ }
if (view instanceof HierarchyHandler) {
final View found = ((HierarchyHandler)view)
.findHierarchyView(className, hashCode);
@@ -823,12 +835,19 @@ public class ViewDebug {
}
}
}
-
return null;
}
private static boolean isRequestedView(View view, String className, int hashCode) {
- return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
+ if (view.hashCode() == hashCode) {
+ String viewClassName = view.getClass().getName();
+ if (className.equals("ViewOverlay")) {
+ return viewClassName.equals("android.view.ViewOverlay$OverlayViewGroup");
+ } else {
+ return className.equals(viewClassName);
+ }
+ }
+ return false;
}
private static void dumpViewHierarchy(Context context, ViewGroup group,
@@ -850,6 +869,12 @@ public class ViewDebug {
} else {
dumpView(context, view, out, level + 1, includeProperties);
}
+ if (view.mOverlay != null) {
+ ViewOverlay overlay = view.getOverlay();
+ ViewGroup overlayContainer = overlay.mOverlayViewGroup;
+ dumpViewHierarchy(context, overlayContainer, out, level + 2, skipChildren,
+ includeProperties);
+ }
}
if (group instanceof HierarchyHandler) {
((HierarchyHandler)group).dumpViewHierarchyWithProperties(out, level + 1);
@@ -863,7 +888,11 @@ public class ViewDebug {
for (int i = 0; i < level; i++) {
out.write(' ');
}
- out.write(view.getClass().getName());
+ String className = view.getClass().getName();
+ if (className.equals("android.view.ViewOverlay$OverlayViewGroup")) {
+ className = "ViewOverlay";
+ }
+ out.write(className);
out.write('@');
out.write(Integer.toHexString(view.hashCode()));
out.write(' ');
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index e6bf420..cea7e49 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -93,11 +93,16 @@ public class ViewPropertyAnimator {
private boolean mInterpolatorSet = false;
/**
- * Listener for the lifecycle events of the underlying
+ * Listener for the lifecycle events of the underlying ValueAnimator object.
*/
private Animator.AnimatorListener mListener = null;
/**
+ * Listener for the update events of the underlying ValueAnimator object.
+ */
+ private ValueAnimator.AnimatorUpdateListener mUpdateListener = null;
+
+ /**
* A lazily-created ValueAnimator used in order to get some default animator properties
* (duration, start delay, interpolator, etc.).
*/
@@ -353,7 +358,10 @@ public class ViewPropertyAnimator {
* Sets a listener for events in the underlying Animators that run the property
* animations.
*
- * @param listener The listener to be called with AnimatorListener events.
+ * @see Animator.AnimatorListener
+ *
+ * @param listener The listener to be called with AnimatorListener events. A value of
+ * <code>null</code> removes any existing listener.
* @return This object, allowing calls to methods in this class to be chained.
*/
public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
@@ -362,6 +370,25 @@ public class ViewPropertyAnimator {
}
/**
+ * Sets a listener for update events in the underlying ValueAnimator that runs
+ * the property animations. Note that the underlying animator is animating between
+ * 0 and 1 (these values are then turned into the actual property values internally
+ * by ViewPropertyAnimator). So the animator cannot give information on the current
+ * values of the properties being animated by this ViewPropertyAnimator, although
+ * the view object itself can be queried to get the current values.
+ *
+ * @see android.animation.ValueAnimator.AnimatorUpdateListener
+ *
+ * @param listener The listener to be called with update events. A value of
+ * <code>null</code> removes any existing listener.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
+ mUpdateListener = listener;
+ return this;
+ }
+
+ /**
* Starts the currently pending property animations immediately. Calling <code>start()</code>
* is optional because all animations start automatically at the next opportunity. However,
* if the animations are needed to start immediately and synchronously (not at the time when
@@ -1073,6 +1100,9 @@ public class ViewPropertyAnimator {
} else {
mView.invalidateViewProperty(false, false);
}
+ if (mUpdateListener != null) {
+ mUpdateListener.onAnimationUpdate(animation);
+ }
}
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index ba63421..c61516b 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -2279,9 +2279,12 @@ public class AccessibilityNodeInfo implements Parcelable {
if (other.mExtras != null && !other.mExtras.isEmpty()) {
getExtras().putAll(other.mExtras);
}
- mRangeInfo = other.mRangeInfo;
- mCollectionInfo = other.mCollectionInfo;
- mCollectionItemInfo = other.mCollectionItemInfo;
+ mRangeInfo = (other.mRangeInfo != null)
+ ? RangeInfo.obtain(other.mRangeInfo) : null;
+ mCollectionInfo = (other.mCollectionInfo != null)
+ ? CollectionInfo.obtain(other.mCollectionInfo) : null;
+ mCollectionItemInfo = (other.mCollectionItemInfo != null)
+ ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
}
/**
@@ -2602,6 +2605,17 @@ public class AccessibilityNodeInfo implements Parcelable {
private float mCurrent;
/**
+ * Obtains a pooled instance that is a clone of another one.
+ *
+ * @param other The instance to clone.
+ *
+ * @hide
+ */
+ public static RangeInfo obtain(RangeInfo other) {
+ return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
+ }
+
+ /**
* Obtains a pooled instance.
*
* @param type The type of the range.
@@ -2708,6 +2722,18 @@ public class AccessibilityNodeInfo implements Parcelable {
private boolean mHierarchical;
/**
+ * Obtains a pooled instance that is a clone of another one.
+ *
+ * @param other The instance to clone.
+ *
+ * @hide
+ */
+ public static CollectionInfo obtain(CollectionInfo other) {
+ return CollectionInfo.obtain(other.mRowCount, other.mColumnCount,
+ other.mHierarchical);
+ }
+
+ /**
* Obtains a pooled instance.
*
* @param rowCount The number of rows.
@@ -2796,6 +2822,18 @@ public class AccessibilityNodeInfo implements Parcelable {
new SynchronizedPool<CollectionItemInfo>(MAX_POOL_SIZE);
/**
+ * Obtains a pooled instance that is a clone of another one.
+ *
+ * @param other The instance to clone.
+ *
+ * @hide
+ */
+ public static CollectionItemInfo obtain(CollectionItemInfo other) {
+ return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan,
+ other.mColumnIndex, other.mColumnSpan, other.mHeading);
+ }
+
+ /**
* Obtains a pooled instance.
*
* @param rowIndex The row index at which the item is located.
diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java
index d4c6abe..557239f 100644
--- a/core/java/android/view/accessibility/CaptioningManager.java
+++ b/core/java/android/view/accessibility/CaptioningManager.java
@@ -140,7 +140,7 @@ public class CaptioningManager {
*
* @param listener the listener to add
*/
- public void addCaptioningStateChangeListener(CaptioningChangeListener listener) {
+ public void addCaptioningChangeListener(CaptioningChangeListener listener) {
synchronized (mListeners) {
if (mListeners.isEmpty()) {
registerObserver(Secure.ACCESSIBILITY_CAPTIONING_ENABLED);
@@ -163,11 +163,11 @@ public class CaptioningManager {
/**
* Removes a listener previously added using
- * {@link #addCaptioningStateChangeListener}.
+ * {@link #addCaptioningChangeListener}.
*
* @param listener the listener to remove
*/
- public void removeCaptioningStateChangeListener(CaptioningChangeListener listener) {
+ public void removeCaptioningChangeListener(CaptioningChangeListener listener) {
synchronized (mListeners) {
mListeners.remove(listener);
@@ -366,7 +366,7 @@ public class CaptioningManager {
* Listener for changes in captioning properties, including enabled state
* and user style preferences.
*/
- public abstract class CaptioningChangeListener {
+ public static abstract class CaptioningChangeListener {
/**
* Called when the captioning enabled state changes.
*
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 29b7cf2..7378d74 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1250,7 +1250,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mFastScroller.setEnabled(true);
}
- recomputePadding();
+ resolvePadding();
if (mFastScroller != null) {
mFastScroller.updateLayout();
@@ -1312,7 +1312,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @see #setFastScrollAlwaysVisible(boolean)
*/
public boolean isFastScrollAlwaysVisible() {
- return mFastScrollEnabled && mFastScrollAlwaysVisible;
+ if (mFastScroller == null) {
+ return mFastScrollEnabled && mFastScrollAlwaysVisible;
+ } else {
+ return mFastScroller.isEnabled() && mFastScroller.isAlwaysShowEnabled();
+ }
}
@Override
@@ -1331,7 +1335,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
@ViewDebug.ExportedProperty
public boolean isFastScrollEnabled() {
- return mFastScrollEnabled;
+ if (mFastScroller == null) {
+ return mFastScrollEnabled;
+ } else {
+ return mFastScroller.isEnabled();
+ }
}
@Override
@@ -1356,7 +1364,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
@Override
protected boolean isVerticalScrollBarHidden() {
- return mFastScrollEnabled;
+ return isFastScrollEnabled();
}
/**
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index c48955f..006b96e 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -152,9 +152,6 @@ class FastScroller {
/** The number of headers at the top of the view. */
private int mHeaderCount;
- /** The number of items in the list. */
- private int mItemCount = -1;
-
/** The index of the current section. */
private int mCurrentSection = -1;
@@ -324,6 +321,7 @@ class FastScroller {
getSectionsFromIndexer();
refreshDrawablePressedState();
+ updateLongList(listView.getChildCount(), listView.getCount());
setScrollbarPosition(mList.getVerticalScrollbarPosition());
postAutoHide();
}
@@ -343,14 +341,10 @@ class FastScroller {
* @param enabled Whether the fast scroll thumb is enabled.
*/
public void setEnabled(boolean enabled) {
- mEnabled = enabled;
+ if (mEnabled != enabled) {
+ mEnabled = enabled;
- if (enabled) {
- if (mAlwaysShow) {
- setState(STATE_VISIBLE);
- }
- } else {
- stop();
+ onStateDependencyChanged();
}
}
@@ -358,19 +352,17 @@ class FastScroller {
* @return Whether the fast scroll thumb is enabled.
*/
public boolean isEnabled() {
- return mEnabled;
+ return mEnabled && (mLongList || mAlwaysShow);
}
/**
* @param alwaysShow Whether the fast scroll thumb should always be shown
*/
public void setAlwaysShow(boolean alwaysShow) {
- mAlwaysShow = alwaysShow;
+ if (mAlwaysShow != alwaysShow) {
+ mAlwaysShow = alwaysShow;
- if (alwaysShow) {
- setState(STATE_VISIBLE);
- } else if (mState == STATE_VISIBLE) {
- postAutoHide();
+ onStateDependencyChanged();
}
}
@@ -382,6 +374,23 @@ class FastScroller {
return mAlwaysShow;
}
+ /**
+ * Called when one of the variables affecting enabled state changes.
+ */
+ private void onStateDependencyChanged() {
+ if (isEnabled()) {
+ if (isAlwaysShowEnabled()) {
+ setState(STATE_VISIBLE);
+ } else if (mState == STATE_VISIBLE) {
+ postAutoHide();
+ }
+ } else {
+ stop();
+ }
+
+ mList.resolvePadding();
+ }
+
public void setScrollBarStyle(int style) {
if (mScrollBarStyle != style) {
mScrollBarStyle = style;
@@ -439,6 +448,18 @@ class FastScroller {
final int firstVisibleItem = mList.getFirstVisiblePosition();
setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount));
}
+
+ updateLongList(visibleItemCount, totalItemCount);
+ }
+
+ private void updateLongList(int visibleItemCount, int totalItemCount) {
+ final boolean longList = visibleItemCount > 0
+ && totalItemCount / visibleItemCount >= MIN_PAGES;
+ if (mLongList != longList) {
+ mLongList = longList;
+
+ onStateDependencyChanged();
+ }
}
/**
@@ -795,19 +816,8 @@ class FastScroller {
mList.postDelayed(mDeferHide, FADE_TIMEOUT);
}
- private boolean isLongList(int visibleItemCount, int totalItemCount) {
- // Are there enough pages to require fast scroll? Recompute only if
- // total count changes.
- if (mItemCount != totalItemCount && visibleItemCount > 0) {
- mItemCount = totalItemCount;
- mLongList = mItemCount / visibleItemCount >= MIN_PAGES;
- }
-
- return mLongList;
- }
-
public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- if (!mEnabled || !mAlwaysShow && !isLongList(visibleItemCount, totalItemCount)) {
+ if (!isEnabled()) {
setState(STATE_NONE);
return;
}
@@ -1221,7 +1231,7 @@ class FastScroller {
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return false;
}
@@ -1233,14 +1243,18 @@ class FastScroller {
// need to allow the parent time to decide whether it wants
// to intercept events. If it does, we will receive a CANCEL
// event.
- if (mList.isInScrollingContainer()) {
- mInitialTouchY = ev.getY();
- startPendingDrag();
- return false;
+ if (!mList.isInScrollingContainer()) {
+ beginDrag();
+ return true;
}
- beginDrag();
- return true;
+ mInitialTouchY = ev.getY();
+ startPendingDrag();
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (!isPointInside(ev.getX(), ev.getY())) {
+ cancelPendingDrag();
}
break;
case MotionEvent.ACTION_UP:
@@ -1253,7 +1267,7 @@ class FastScroller {
}
public boolean onInterceptHoverEvent(MotionEvent ev) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return false;
}
@@ -1269,18 +1283,11 @@ class FastScroller {
}
public boolean onTouchEvent(MotionEvent me) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return false;
}
switch (me.getActionMasked()) {
- case MotionEvent.ACTION_DOWN: {
- if (isPointInside(me.getX(), me.getY())) {
- beginDrag();
- return true;
- }
- } break;
-
case MotionEvent.ACTION_UP: {
if (mHasPendingDrag) {
// Allow a tap to scroll.
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index f449797..009b729 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -30,6 +30,7 @@ import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.Metadata;
import android.media.SubtitleController;
+import android.media.SubtitleTrack.RenderingWidget;
import android.media.WebVttRenderer;
import android.net.Uri;
import android.util.AttributeSet;
@@ -46,7 +47,6 @@ import android.widget.MediaController.MediaPlayerControl;
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
import java.util.Map;
import java.util.Vector;
@@ -100,14 +100,11 @@ public class VideoView extends SurfaceView
private boolean mCanSeekBack;
private boolean mCanSeekForward;
- /** List of views overlaid on top of the video. */
- private ArrayList<View> mOverlays;
+ /** Subtitle rendering widget overlaid on top of the video. */
+ private RenderingWidget mSubtitleWidget;
- /**
- * Listener for overlay layout changes. Invalidates the video view to ensure
- * that captions are redrawn whenever their layout changes.
- */
- private OnLayoutChangeListener mOverlayLayoutListener;
+ /** Listener for changes to subtitle data, used to redraw when needed. */
+ private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
public VideoView(Context context) {
super(context);
@@ -302,11 +299,10 @@ public class VideoView extends SurfaceView
mMediaPlayer = new MediaPlayer();
// TODO: create SubtitleController in MediaPlayer, but we need
// a context for the subtitle renderers
- SubtitleController controller = new SubtitleController(
- getContext(),
- mMediaPlayer.getMediaTimeProvider(),
- mMediaPlayer);
- controller.registerRenderer(new WebVttRenderer(getContext(), null));
+ final Context context = getContext();
+ final SubtitleController controller = new SubtitleController(
+ context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
+ controller.registerRenderer(new WebVttRenderer(context));
mMediaPlayer.setSubtitleAnchor(controller, this);
if (mAudioSession != 0) {
@@ -792,117 +788,95 @@ public class VideoView extends SurfaceView
}
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
- // Layout overlay views, if necessary.
- if (changed && mOverlays != null && !mOverlays.isEmpty()) {
- measureAndLayoutOverlays();
+ if (mSubtitleWidget != null) {
+ mSubtitleWidget.onAttachedToWindow();
}
}
@Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
- final int count = mOverlays.size();
- for (int i = 0; i < count; i++) {
- final View overlay = mOverlays.get(i);
- overlay.draw(canvas);
+ if (mSubtitleWidget != null) {
+ mSubtitleWidget.onDetachedFromWindow();
}
}
- /**
- * Adds a view to be overlaid on top of this video view. During layout, the
- * view will be forced to match the bounds, less padding, of the video view.
- * <p>
- * Overlays are drawn in the order they are added. The last added overlay
- * will be drawn on top.
- *
- * @param overlay the view to overlay
- * @see #removeOverlay(View)
- */
- private void addOverlay(View overlay) {
- if (mOverlays == null) {
- mOverlays = new ArrayList<View>(1);
- }
-
- if (mOverlayLayoutListener == null) {
- mOverlayLayoutListener = new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- invalidate();
- }
- };
- }
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
- if (mOverlays.isEmpty()) {
- setWillNotDraw(false);
+ if (mSubtitleWidget != null) {
+ measureAndLayoutSubtitleWidget();
}
-
- mOverlays.add(overlay);
- overlay.addOnLayoutChangeListener(mOverlayLayoutListener);
- measureAndLayoutOverlays();
}
- /**
- * Removes a view previously added using {@link #addOverlay}.
- *
- * @param overlay the view to remove
- * @see #addOverlay(View)
- */
- private void removeOverlay(View overlay) {
- if (mOverlays == null) {
- return;
- }
-
- overlay.removeOnLayoutChangeListener(mOverlayLayoutListener);
- mOverlays.remove(overlay);
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
- if (mOverlays.isEmpty()) {
- setWillNotDraw(true);
+ if (mSubtitleWidget != null) {
+ final int saveCount = canvas.save();
+ canvas.translate(getPaddingLeft(), getPaddingTop());
+ mSubtitleWidget.draw(canvas);
+ canvas.restoreToCount(saveCount);
}
-
- invalidate();
}
/**
* Forces a measurement and layout pass for all overlaid views.
*
- * @see #addOverlay(View)
+ * @see #setSubtitleWidget(RenderingWidget)
*/
- private void measureAndLayoutOverlays() {
- final int left = getPaddingLeft();
- final int top = getPaddingTop();
- final int right = getWidth() - left - getPaddingRight();
- final int bottom = getHeight() - top - getPaddingBottom();
- final int widthSpec = MeasureSpec.makeMeasureSpec(right - left, MeasureSpec.EXACTLY);
- final int heightSpec = MeasureSpec.makeMeasureSpec(bottom - top, MeasureSpec.EXACTLY);
+ private void measureAndLayoutSubtitleWidget() {
+ final int width = getWidth() - getPaddingLeft() - getPaddingRight();
+ final int height = getHeight() - getPaddingTop() - getPaddingBottom();
- final int count = mOverlays.size();
- for (int i = 0; i < count; i++) {
- final View overlay = mOverlays.get(i);
- overlay.measure(widthSpec, heightSpec);
- overlay.layout(left, top, right, bottom);
- }
+ mSubtitleWidget.setSize(width, height);
}
/** @hide */
@Override
- public void setSubtitleView(View view) {
- if (mSubtitleView == view) {
+ public void setSubtitleWidget(RenderingWidget subtitleWidget) {
+ if (mSubtitleWidget == subtitleWidget) {
return;
}
- if (mSubtitleView != null) {
- removeOverlay(mSubtitleView);
+ final boolean attachedToWindow = isAttachedToWindow();
+ if (mSubtitleWidget != null) {
+ if (attachedToWindow) {
+ mSubtitleWidget.onDetachedFromWindow();
+ }
+
+ mSubtitleWidget.setOnChangedListener(null);
}
- mSubtitleView = view;
- if (mSubtitleView != null) {
- addOverlay(mSubtitleView);
+
+ mSubtitleWidget = subtitleWidget;
+
+ if (subtitleWidget != null) {
+ if (mSubtitlesChangedListener == null) {
+ mSubtitlesChangedListener = new RenderingWidget.OnChangedListener() {
+ @Override
+ public void onChanged(RenderingWidget renderingWidget) {
+ invalidate();
+ }
+ };
+ }
+
+ setWillNotDraw(false);
+ subtitleWidget.setOnChangedListener(mSubtitlesChangedListener);
+
+ if (attachedToWindow) {
+ subtitleWidget.onAttachedToWindow();
+ requestLayout();
+ }
+ } else {
+ setWillNotDraw(true);
}
- }
- private View mSubtitleView;
+ invalidate();
+ }
}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 16b119a..1f55a4c 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -165,7 +165,7 @@ public final class ProcessStats implements Parcelable {
static final String CSV_SEP = "\t";
// Current version of the parcel format.
- private static final int PARCEL_VERSION = 9;
+ private static final int PARCEL_VERSION = 11;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0x50535453;
@@ -204,6 +204,12 @@ public final class ProcessStats implements Parcelable {
int[] mAddLongTable;
int mAddLongTableSize;
+ // For writing parcels.
+ ArrayMap<String, Integer> mCommonStringToIndex;
+
+ // For reading parcels.
+ ArrayList<String> mIndexToCommonString;
+
public ProcessStats(boolean running) {
mRunning = running;
reset();
@@ -247,7 +253,7 @@ public final class ProcessStats implements Parcelable {
if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
+ " service " + otherSvc.mName);
ServiceState thisSvc = getServiceStateLocked(pkgName, uid,
- null, otherSvc.mName);
+ otherSvc.mProcessName, otherSvc.mName);
thisSvc.add(otherSvc);
}
}
@@ -959,7 +965,15 @@ public final class ProcessStats implements Parcelable {
for (int ip=procMap.size()-1; ip>=0; ip--) {
SparseArray<ProcessState> uids = procMap.valueAt(ip);
for (int iu=uids.size()-1; iu>=0; iu--) {
- uids.valueAt(iu).resetSafely(now);
+ ProcessState ps = uids.valueAt(iu);
+ if (ps.isInUse()) {
+ uids.valueAt(iu).resetSafely(now);
+ } else {
+ uids.removeAt(iu);
+ }
+ }
+ if (uids.size() <= 0) {
+ procMap.removeAt(ip);
}
}
ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
@@ -968,16 +982,27 @@ public final class ProcessStats implements Parcelable {
for (int iu=uids.size()-1; iu>=0; iu--) {
PackageState pkgState = uids.valueAt(iu);
for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
- pkgState.mProcesses.valueAt(iproc).resetSafely(now);
+ ProcessState ps = pkgState.mProcesses.valueAt(iproc);
+ if (ps.isInUse()) {
+ pkgState.mProcesses.valueAt(iproc).resetSafely(now);
+ } else {
+ pkgState.mProcesses.removeAt(iproc);
+ }
}
for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
ServiceState ss = pkgState.mServices.valueAt(isvc);
- if (ss.isActive()) {
+ if (ss.isInUse()) {
pkgState.mServices.valueAt(isvc).resetSafely(now);
} else {
pkgState.mServices.removeAt(isvc);
}
}
+ if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0) {
+ uids.removeAt(iu);
+ }
+ }
+ if (uids.size() <= 0) {
+ pkgMap.removeAt(ip);
}
}
mStartTime = SystemClock.uptimeMillis();
@@ -1048,6 +1073,75 @@ public final class ProcessStats implements Parcelable {
return table;
}
+ private void writeCompactedLongArray(Parcel out, long[] array) {
+ final int N = array.length;
+ out.writeInt(N);
+ for (int i=0; i<N; i++) {
+ long val = array[i];
+ if (val < 0) {
+ Slog.w(TAG, "Time val negative: " + val);
+ val = 0;
+ }
+ if (val <= Integer.MAX_VALUE) {
+ out.writeInt((int)val);
+ } else {
+ int top = ~((int)((val>>32)&0x7fffffff));
+ int bottom = (int)(val&0xfffffff);
+ out.writeInt(top);
+ out.writeInt(bottom);
+ }
+ }
+ }
+
+ private void readCompactedLongArray(Parcel in, int version, long[] array) {
+ if (version <= 10) {
+ in.readLongArray(array);
+ return;
+ }
+ final int N = in.readInt();
+ if (N != array.length) {
+ throw new RuntimeException("bad array lengths");
+ }
+ for (int i=0; i<N; i++) {
+ int val = in.readInt();
+ if (val >= 0) {
+ array[i] = val;
+ } else {
+ int bottom = in.readInt();
+ array[i] = (((long)~val)<<32) | bottom;
+ }
+ }
+ }
+
+ private void writeCommonString(Parcel out, String name) {
+ Integer index = mCommonStringToIndex.get(name);
+ if (index != null) {
+ out.writeInt(index);
+ return;
+ }
+ index = mCommonStringToIndex.size();
+ mCommonStringToIndex.put(name, index);
+ out.writeInt(~index);
+ out.writeString(name);
+ }
+
+ private String readCommonString(Parcel in, int version) {
+ if (version <= 9) {
+ return in.readString();
+ }
+ int index = in.readInt();
+ if (index >= 0) {
+ return mIndexToCommonString.get(index);
+ }
+ index = ~index;
+ String name = in.readString();
+ while (mIndexToCommonString.size() <= index) {
+ mIndexToCommonString.add(null);
+ }
+ mIndexToCommonString.set(index, name);
+ return name;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -1063,6 +1157,8 @@ public final class ProcessStats implements Parcelable {
out.writeInt(PSS_COUNT);
out.writeInt(LONGS_SIZE);
+ mCommonStringToIndex = new ArrayMap<String, Integer>(mProcesses.mMap.size());
+
// First commit all running times.
ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
final int NPROC = procMap.size();
@@ -1104,7 +1200,7 @@ public final class ProcessStats implements Parcelable {
out.writeInt(mLongs.size());
out.writeInt(mNextLong);
for (int i=0; i<(mLongs.size()-1); i++) {
- out.writeLongArray(mLongs.get(i));
+ writeCompactedLongArray(out, mLongs.get(i));
}
long[] lastLongs = mLongs.get(mLongs.size() - 1);
for (int i=0; i<mNextLong; i++) {
@@ -1116,24 +1212,24 @@ public final class ProcessStats implements Parcelable {
mMemFactorDurations[mMemFactor] += now - mStartTime;
mStartTime = now;
}
- out.writeLongArray(mMemFactorDurations);
+ writeCompactedLongArray(out, mMemFactorDurations);
out.writeInt(NPROC);
for (int ip=0; ip<NPROC; ip++) {
- out.writeString(procMap.keyAt(ip));
+ writeCommonString(out, procMap.keyAt(ip));
SparseArray<ProcessState> uids = procMap.valueAt(ip);
final int NUID = uids.size();
out.writeInt(NUID);
for (int iu=0; iu<NUID; iu++) {
out.writeInt(uids.keyAt(iu));
ProcessState proc = uids.valueAt(iu);
- out.writeString(proc.mPackage);
+ writeCommonString(out, proc.mPackage);
proc.writeToParcel(out, now);
}
}
out.writeInt(NPKG);
for (int ip=0; ip<NPKG; ip++) {
- out.writeString(pkgMap.keyAt(ip));
+ writeCommonString(out, pkgMap.keyAt(ip));
SparseArray<PackageState> uids = pkgMap.valueAt(ip);
final int NUID = uids.size();
out.writeInt(NUID);
@@ -1143,7 +1239,7 @@ public final class ProcessStats implements Parcelable {
final int NPROCS = pkgState.mProcesses.size();
out.writeInt(NPROCS);
for (int iproc=0; iproc<NPROCS; iproc++) {
- out.writeString(pkgState.mProcesses.keyAt(iproc));
+ writeCommonString(out, pkgState.mProcesses.keyAt(iproc));
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
if (proc.mCommonProcess == proc) {
// This is the same as the common process we wrote above.
@@ -1159,10 +1255,13 @@ public final class ProcessStats implements Parcelable {
for (int isvc=0; isvc<NSRVS; isvc++) {
out.writeString(pkgState.mServices.keyAt(isvc));
ServiceState svc = pkgState.mServices.valueAt(isvc);
+ writeCommonString(out, svc.mProcessName);
svc.writeToParcel(out, now);
}
}
}
+
+ mCommonStringToIndex = null;
}
private boolean readCheckedInt(Parcel in, int val, String what) {
@@ -1222,7 +1321,7 @@ public final class ProcessStats implements Parcelable {
return;
}
int version = in.readInt();
- if (version != PARCEL_VERSION && version != 6) {
+ if (version != PARCEL_VERSION) {
mReadError = "bad version: " + version;
return;
}
@@ -1239,14 +1338,14 @@ public final class ProcessStats implements Parcelable {
return;
}
+ mIndexToCommonString = new ArrayList<String>();
+
mTimePeriodStartClock = in.readLong();
buildTimePeriodStartClockStr();
mTimePeriodStartRealtime = in.readLong();
mTimePeriodEndRealtime = in.readLong();
- if (version == PARCEL_VERSION) {
- mRuntime = in.readString();
- mWebView = in.readString();
- }
+ mRuntime = in.readString();
+ mWebView = in.readString();
mFlags = in.readInt();
final int NLONGS = in.readInt();
@@ -1256,7 +1355,7 @@ public final class ProcessStats implements Parcelable {
while (i >= mLongs.size()) {
mLongs.add(new long[LONGS_SIZE]);
}
- in.readLongArray(mLongs.get(i));
+ readCompactedLongArray(in, version, mLongs.get(i));
}
long[] longs = new long[LONGS_SIZE];
mNextLong = NEXTLONG;
@@ -1266,7 +1365,7 @@ public final class ProcessStats implements Parcelable {
}
mLongs.add(longs);
- in.readLongArray(mMemFactorDurations);
+ readCompactedLongArray(in, version, mMemFactorDurations);
int NPROC = in.readInt();
if (NPROC < 0) {
@@ -1275,7 +1374,7 @@ public final class ProcessStats implements Parcelable {
}
while (NPROC > 0) {
NPROC--;
- String procName = in.readString();
+ String procName = readCommonString(in, version);
if (procName == null) {
mReadError = "bad process name";
return;
@@ -1292,7 +1391,7 @@ public final class ProcessStats implements Parcelable {
mReadError = "bad uid: " + uid;
return;
}
- String pkgName = in.readString();
+ String pkgName = readCommonString(in, version);
if (pkgName == null) {
mReadError = "bad process package name";
return;
@@ -1322,7 +1421,7 @@ public final class ProcessStats implements Parcelable {
}
while (NPKG > 0) {
NPKG--;
- String pkgName = in.readString();
+ String pkgName = readCommonString(in, version);
if (pkgName == null) {
mReadError = "bad package name";
return;
@@ -1348,7 +1447,7 @@ public final class ProcessStats implements Parcelable {
}
while (NPROCS > 0) {
NPROCS--;
- String procName = in.readString();
+ String procName = readCommonString(in, version);
if (procName == null) {
mReadError = "bad package process name";
return;
@@ -1400,9 +1499,10 @@ public final class ProcessStats implements Parcelable {
mReadError = "bad package service name";
return;
}
+ String processName = version > 9 ? readCommonString(in, version) : null;
ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null;
if (serv == null) {
- serv = new ServiceState(this, pkgName, serviceName, null);
+ serv = new ServiceState(this, pkgName, serviceName, processName, null);
}
if (!serv.readFromParcel(in)) {
return;
@@ -1414,6 +1514,8 @@ public final class ProcessStats implements Parcelable {
}
}
+ mIndexToCommonString = null;
+
if (DEBUG) Slog.d(TAG, "Successfully read procstats!");
}
@@ -1555,12 +1657,11 @@ public final class ProcessStats implements Parcelable {
final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid);
ProcessStats.ServiceState ss = as.mServices.get(className);
if (ss != null) {
- ss.makeActive();
return ss;
}
final ProcessStats.ProcessState ps = processName != null
? getProcessStateLocked(packageName, uid, processName) : null;
- ss = new ProcessStats.ServiceState(this, packageName, className, ps);
+ ss = new ProcessStats.ServiceState(this, packageName, className, processName, ps);
as.mServices.put(className, ss);
return ss;
}
@@ -1602,10 +1703,10 @@ public final class ProcessStats implements Parcelable {
ALL_PROC_STATES, now);
dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
ALL_PROC_STATES);
- if (dumpAll) {
- pw.print(" mNumStartedServices=");
- pw.println(proc.mNumStartedServices);
- }
+ pw.print(" mActive="); pw.println(proc.mActive);
+ pw.print(" mNumActiveServices="); pw.print(proc.mNumActiveServices);
+ pw.print(" mNumStartedServices=");
+ pw.println(proc.mNumStartedServices);
}
} else {
ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
@@ -1624,6 +1725,9 @@ public final class ProcessStats implements Parcelable {
pw.print(pkgState.mServices.keyAt(isvc));
pw.println(":");
ServiceState svc = pkgState.mServices.valueAt(isvc);
+ dumpServiceStats(pw, " ", " ", " ", "Running", svc,
+ svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
+ svc.mRunStartTime, now, totalTime, dumpAll);
dumpServiceStats(pw, " ", " ", " ", "Started", svc,
svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
svc.mStartedStartTime, now, totalTime, dumpAll);
@@ -1633,6 +1737,9 @@ public final class ProcessStats implements Parcelable {
dumpServiceStats(pw, " ", " ", " ", "Executing", svc,
svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
svc.mExecStartTime, now, totalTime, dumpAll);
+ if (dumpAll) {
+ pw.print(" mActive="); pw.println(svc.mActive);
+ }
}
}
}
@@ -1663,6 +1770,12 @@ public final class ProcessStats implements Parcelable {
ALL_PROC_STATES, now);
dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
ALL_PROC_STATES);
+ if (dumpAll) {
+ pw.print(" mActive="); pw.println(proc.mActive);
+ pw.print(" mNumActiveServices="); pw.print(proc.mNumActiveServices);
+ pw.print(" mNumStartedServices=");
+ pw.println(proc.mNumStartedServices);
+ }
}
}
@@ -1929,6 +2042,9 @@ public final class ProcessStats implements Parcelable {
String serviceName = collapseString(pkgName,
pkgState.mServices.keyAt(isvc));
ServiceState svc = pkgState.mServices.valueAt(isvc);
+ dumpServiceTimeCheckin(pw, "pkgsvc-run", pkgName, uid, serviceName,
+ svc, ServiceState.SERVICE_RUN, svc.mRunCount,
+ svc.mRunState, svc.mRunStartTime, now);
dumpServiceTimeCheckin(pw, "pkgsvc-start", pkgName, uid, serviceName,
svc, ServiceState.SERVICE_STARTED, svc.mStartedCount,
svc.mStartedState, svc.mStartedStartTime, now);
@@ -2003,6 +2119,8 @@ public final class ProcessStats implements Parcelable {
int[] mPssTable;
int mPssTableSize;
+ boolean mActive;
+ int mNumActiveServices;
int mNumStartedServices;
int mNumExcessiveWake;
@@ -2072,6 +2190,7 @@ public final class ProcessStats implements Parcelable {
}
pnew.mNumExcessiveWake = mNumExcessiveWake;
pnew.mNumExcessiveCpu = mNumExcessiveCpu;
+ pnew.mActive = mActive;
pnew.mNumStartedServices = mNumStartedServices;
return pnew;
}
@@ -2151,6 +2270,18 @@ public final class ProcessStats implements Parcelable {
return true;
}
+ public void makeActive() {
+ mActive = true;
+ }
+
+ public void makeInactive() {
+ mActive = false;
+ }
+
+ public boolean isInUse() {
+ return mActive || mNumActiveServices > 0 || mNumStartedServices > 0;
+ }
+
/**
* Update the current state of the given list of processes.
*
@@ -2219,6 +2350,24 @@ public final class ProcessStats implements Parcelable {
longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
}
+ void incActiveServices() {
+ if (mCommonProcess != this) {
+ mCommonProcess.incActiveServices();
+ }
+ mNumActiveServices++;
+ }
+
+ void decActiveServices() {
+ if (mCommonProcess != this) {
+ mCommonProcess.decActiveServices();
+ }
+ mNumActiveServices--;
+ if (mNumActiveServices < 0) {
+ throw new IllegalStateException("Proc active services underrun: pkg="
+ + mPackage + " uid=" + mUid + " name=" + mName);
+ }
+ }
+
void incStartedServices(int memFactor, long now) {
if (mCommonProcess != this) {
mCommonProcess.incStartedServices(memFactor, now);
@@ -2406,18 +2555,24 @@ public final class ProcessStats implements Parcelable {
final ProcessStats mStats;
public final String mPackage;
public final String mName;
+ public final String mProcessName;
ProcessState mProc;
- int mActive = 1;
+ int mActive = 0;
- public static final int SERVICE_STARTED = 0;
- public static final int SERVICE_BOUND = 1;
- public static final int SERVICE_EXEC = 2;
- static final int SERVICE_COUNT = 3;
+ public static final int SERVICE_RUN = 0;
+ public static final int SERVICE_STARTED = 1;
+ public static final int SERVICE_BOUND = 2;
+ public static final int SERVICE_EXEC = 3;
+ static final int SERVICE_COUNT = 4;
int[] mDurationsTable;
int mDurationsTableSize;
+ int mRunCount;
+ public int mRunState = STATE_NOTHING;
+ long mRunStartTime;
+
int mStartedCount;
public int mStartedState = STATE_NOTHING;
long mStartedStartTime;
@@ -2430,14 +2585,19 @@ public final class ProcessStats implements Parcelable {
public int mExecState = STATE_NOTHING;
long mExecStartTime;
- public ServiceState(ProcessStats processStats, String pkg, String name, ProcessState proc) {
+ public ServiceState(ProcessStats processStats, String pkg, String name,
+ String processName, ProcessState proc) {
mStats = processStats;
mPackage = pkg;
mName = name;
+ mProcessName = processName;
mProc = proc;
}
public void makeActive() {
+ if (mActive == 0) {
+ mProc.incActiveServices();
+ }
mActive++;
}
@@ -2448,9 +2608,12 @@ public final class ProcessStats implements Parcelable {
Slog.i(TAG, "Making " + this + " inactive", here);
*/
mActive--;
+ if (mActive == 0) {
+ mProc.decActiveServices();
+ }
}
- public boolean isActive() {
+ public boolean isInUse() {
return mActive > 0;
}
@@ -2460,6 +2623,7 @@ public final class ProcessStats implements Parcelable {
int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
addStateTime(state, other.mStats.getLong(ent, 0));
}
+ mRunCount += other.mRunCount;
mStartedCount += other.mStartedCount;
mBoundCount += other.mBoundCount;
mExecCount += other.mExecCount;
@@ -2468,6 +2632,7 @@ public final class ProcessStats implements Parcelable {
void resetSafely(long now) {
mDurationsTable = null;
mDurationsTableSize = 0;
+ mRunCount = mRunState != STATE_NOTHING ? 1 : 0;
mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
@@ -2481,6 +2646,7 @@ public final class ProcessStats implements Parcelable {
+ printLongOffset(mDurationsTable[i]));
out.writeInt(mDurationsTable[i]);
}
+ out.writeInt(mRunCount);
out.writeInt(mStartedCount);
out.writeInt(mBoundCount);
out.writeInt(mExecCount);
@@ -2493,6 +2659,7 @@ public final class ProcessStats implements Parcelable {
return false;
}
mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
+ mRunCount = in.readInt();
mStartedCount = in.readInt();
mBoundCount = in.readInt();
mExecCount = in.readInt();
@@ -2518,6 +2685,10 @@ public final class ProcessStats implements Parcelable {
}
void commitStateTime(long now) {
+ if (mRunState != STATE_NOTHING) {
+ addStateTime(SERVICE_RUN + (mRunState*SERVICE_COUNT), now - mRunStartTime);
+ mRunStartTime = now;
+ }
if (mStartedState != STATE_NOTHING) {
addStateTime(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
now - mStartedStartTime);
@@ -2533,6 +2704,21 @@ public final class ProcessStats implements Parcelable {
}
}
+ private void updateRunning(int memFactor, long now) {
+ final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
+ || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
+ if (mRunState != state) {
+ if (mRunState != STATE_NOTHING) {
+ addStateTime(SERVICE_RUN + (mRunState*SERVICE_COUNT),
+ now - mRunStartTime);
+ } else if (state != STATE_NOTHING) {
+ mRunCount++;
+ }
+ mRunState = state;
+ mRunStartTime = now;
+ }
+ }
+
public void setStarted(boolean started, int memFactor, long now) {
if (mActive <= 0) {
throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
@@ -2556,6 +2742,7 @@ public final class ProcessStats implements Parcelable {
mProc.decStartedServices(memFactor, now);
}
}
+ updateRunning(memFactor, now);
}
}
@@ -2573,6 +2760,7 @@ public final class ProcessStats implements Parcelable {
}
mBoundState = state;
mBoundStartTime = now;
+ updateRunning(memFactor, now);
}
}
@@ -2589,6 +2777,7 @@ public final class ProcessStats implements Parcelable {
}
mExecState = state;
mExecStartTime = now;
+ updateRunning(memFactor, now);
}
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index a85d5fe..5538dca 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -17,6 +17,7 @@
package com.android.internal.os;
import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
import android.os.Build;
import android.os.Debug;
@@ -69,7 +70,14 @@ public class RuntimeInit {
if (mApplicationObject == null) {
Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
} else {
- Slog.e(TAG, "FATAL EXCEPTION: " + t.getName(), e);
+ StringBuilder message = new StringBuilder();
+ message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
+ final String processName = ActivityThread.currentProcessName();
+ if (processName != null) {
+ message.append("Process: ").append(processName).append(", ");
+ }
+ message.append("PID: ").append(Process.myPid());
+ Slog.e(TAG, message.toString(), e);
}
// Bring up crash dialog, wait for it to be dismissed
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index f060efd..c1ae9c2 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -156,7 +156,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter
}
@Override
- public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
+ public View getItemView(final MenuItemImpl item, View convertView, ViewGroup parent) {
View actionView = item.getActionView();
if (actionView == null || item.hasCollapsibleActionView()) {
if (!(convertView instanceof ActionMenuItemView)) {
@@ -166,6 +166,27 @@ public class ActionMenuPresenter extends BaseMenuPresenter
}
actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
+ if (item.hasSubMenu()) {
+ actionView.setOnTouchListener(new ForwardingListener(actionView) {
+ @Override
+ public ListPopupWindow getPopup() {
+ return mActionButtonPopup != null ? mActionButtonPopup.getPopup() : null;
+ }
+
+ @Override
+ protected boolean onForwardingStarted() {
+ return onSubMenuSelected((SubMenuBuilder) item.getSubMenu());
+ }
+
+ @Override
+ protected boolean onForwardingStopped() {
+ return dismissPopupMenus();
+ }
+ });
+ } else {
+ actionView.setOnTouchListener(null);
+ }
+
final ActionMenuView menuParent = (ActionMenuView) parent;
final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
if (!menuParent.checkLayoutParams(lp)) {
diff --git a/core/java/com/android/internal/widget/AutoScrollHelper.java b/core/java/com/android/internal/widget/AutoScrollHelper.java
index afa4103..7a294aa 100644
--- a/core/java/com/android/internal/widget/AutoScrollHelper.java
+++ b/core/java/com/android/internal/widget/AutoScrollHelper.java
@@ -66,7 +66,7 @@ import android.widget.AbsListView;
* The following scrolling properties may be configured:
* <ul>
* <li>Acceleration ramp-up duration, see {@link #setRampUpDuration}. Default
- * value is 2500 milliseconds.
+ * value is 500 milliseconds.
* <li>Acceleration ramp-down duration, see {@link #setRampDownDuration}.
* Default value is 500 milliseconds.
* <li>Target velocity relative to view size, see {@link #setRelativeVelocity}.
@@ -191,7 +191,7 @@ public abstract class AutoScrollHelper implements View.OnTouchListener {
private static final float DEFAULT_RELATIVE_EDGE = 0.2f;
private static final float DEFAULT_RELATIVE_VELOCITY = 1f;
private static final int DEFAULT_ACTIVATION_DELAY = ViewConfiguration.getTapTimeout();
- private static final int DEFAULT_RAMP_UP_DURATION = 2500;
+ private static final int DEFAULT_RAMP_UP_DURATION = 500;
private static final int DEFAULT_RAMP_DOWN_DURATION = 500;
/**
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index 13101512..356401c 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -74,6 +74,10 @@ public class SubtitleView extends View {
private float mSpacingAdd = 0;
private int mInnerPaddingX = 0;
+ public SubtitleView(Context context) {
+ this(context, null);
+ }
+
public SubtitleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a17b301..490d85c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -53,6 +53,7 @@ extern int register_android_graphics_Bitmap(JNIEnv*);
extern int register_android_graphics_BitmapFactory(JNIEnv*);
extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
extern int register_android_graphics_Camera(JNIEnv* env);
+extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
extern int register_android_graphics_Graphics(JNIEnv* env);
extern int register_android_graphics_Interpolator(JNIEnv* env);
extern int register_android_graphics_LayerRasterizer(JNIEnv*);
@@ -1137,6 +1138,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_BitmapFactory),
REG_JNI(register_android_graphics_BitmapRegionDecoder),
REG_JNI(register_android_graphics_Camera),
+ REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
REG_JNI(register_android_graphics_Canvas),
REG_JNI(register_android_graphics_ColorFilter),
REG_JNI(register_android_graphics_DrawFilter),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 16beb02..f9bb233 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -189,7 +189,13 @@ public:
mSize, bitmap->getSize());
return false;
}
- bitmap->setPixelRef(mPixelRef);
+
+ // Create a new pixelref with the new ctable that wraps the previous pixelref
+ SkPixelRef* pr = new AndroidPixelRef(*static_cast<AndroidPixelRef*>(mPixelRef), ctable);
+
+ bitmap->setPixelRef(pr)->unref();
+ // since we're already allocated, we lockPixels right away
+ // HeapAllocator/JavaPixelAllocator behaves this way too
bitmap->lockPixels();
return true;
}
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index d264392..2d06b68 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -7,12 +7,6 @@
#include "Utils.h"
#include <androidfw/Asset.h>
-#define RETURN_NULL_IF_NULL(value) \
- do { if (!(value)) { SkASSERT(0); return NULL; } } while (false)
-
-#define RETURN_ZERO_IF_NULL(value) \
- do { if (!(value)) { SkASSERT(0); return 0; } } while (false)
-
static jmethodID gInputStream_resetMethodID;
static jmethodID gInputStream_markMethodID;
static jmethodID gInputStream_markSupportedMethodID;
@@ -161,32 +155,6 @@ private:
SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
jbyteArray storage) {
- static bool gInited;
-
- if (!gInited) {
- jclass inputStream_Clazz = env->FindClass("java/io/InputStream");
- RETURN_NULL_IF_NULL(inputStream_Clazz);
-
- gInputStream_resetMethodID = env->GetMethodID(inputStream_Clazz,
- "reset", "()V");
- gInputStream_markMethodID = env->GetMethodID(inputStream_Clazz,
- "mark", "(I)V");
- gInputStream_markSupportedMethodID = env->GetMethodID(inputStream_Clazz,
- "markSupported", "()Z");
- gInputStream_readMethodID = env->GetMethodID(inputStream_Clazz,
- "read", "([BII)I");
- gInputStream_skipMethodID = env->GetMethodID(inputStream_Clazz,
- "skip", "(J)J");
-
- RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
- RETURN_NULL_IF_NULL(gInputStream_markMethodID);
- RETURN_NULL_IF_NULL(gInputStream_markSupportedMethodID);
- RETURN_NULL_IF_NULL(gInputStream_readMethodID);
- RETURN_NULL_IF_NULL(gInputStream_skipMethodID);
-
- gInited = true;
- }
-
return new JavaInputStreamAdaptor(env, stream, storage);
}
@@ -263,27 +231,19 @@ private:
const size_t fLength;
};
+static jclass gByteArrayInputStream_Clazz;
+static jfieldID gCountField;
+static jfieldID gPosField;
+
/**
* If jstream is a ByteArrayInputStream, return its remaining length. Otherwise
* return 0.
*/
static size_t get_length_from_byte_array_stream(JNIEnv* env, jobject jstream) {
- static jclass byteArrayInputStream_Clazz;
- static jfieldID countField;
- static jfieldID posField;
-
- byteArrayInputStream_Clazz = env->FindClass("java/io/ByteArrayInputStream");
- RETURN_ZERO_IF_NULL(byteArrayInputStream_Clazz);
-
- countField = env->GetFieldID(byteArrayInputStream_Clazz, "count", "I");
- RETURN_ZERO_IF_NULL(byteArrayInputStream_Clazz);
- posField = env->GetFieldID(byteArrayInputStream_Clazz, "pos", "I");
- RETURN_ZERO_IF_NULL(byteArrayInputStream_Clazz);
-
- if (env->IsInstanceOf(jstream, byteArrayInputStream_Clazz)) {
+ if (env->IsInstanceOf(jstream, gByteArrayInputStream_Clazz)) {
// Return the remaining length, to keep the same behavior of using the rest of the
// stream.
- return env->GetIntField(jstream, countField) - env->GetIntField(jstream, posField);
+ return env->GetIntField(jstream, gCountField) - env->GetIntField(jstream, gPosField);
}
return 0;
}
@@ -321,21 +281,15 @@ SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream,
return adaptor_to_mem_stream(adaptor.get());
}
-android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject jstream) {
- static jclass assetInputStream_Clazz;
- static jmethodID getAssetIntMethodID;
-
- assetInputStream_Clazz = env->FindClass("android/content/res/AssetManager$AssetInputStream");
- RETURN_NULL_IF_NULL(assetInputStream_Clazz);
-
- getAssetIntMethodID = env->GetMethodID(assetInputStream_Clazz, "getAssetInt", "()I");
- RETURN_NULL_IF_NULL(getAssetIntMethodID);
+static jclass gAssetInputStream_Clazz;
+static jmethodID gGetAssetIntMethodID;
- if (!env->IsInstanceOf(jstream, assetInputStream_Clazz)) {
+android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject jstream) {
+ if (!env->IsInstanceOf(jstream, gAssetInputStream_Clazz)) {
return NULL;
}
- jint jasset = env->CallIntMethod(jstream, getAssetIntMethodID);
+ jint jasset = env->CallIntMethod(jstream, gGetAssetIntMethodID);
android::Asset* a = reinterpret_cast<android::Asset*>(jasset);
if (NULL == a) {
jniThrowNullPointerException(env, "NULL native asset");
@@ -406,18 +360,57 @@ SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
static bool gInited;
if (!gInited) {
- jclass outputStream_Clazz = env->FindClass("java/io/OutputStream");
- RETURN_NULL_IF_NULL(outputStream_Clazz);
-
- gOutputStream_writeMethodID = env->GetMethodID(outputStream_Clazz,
- "write", "([BII)V");
- RETURN_NULL_IF_NULL(gOutputStream_writeMethodID);
- gOutputStream_flushMethodID = env->GetMethodID(outputStream_Clazz,
- "flush", "()V");
- RETURN_NULL_IF_NULL(gOutputStream_flushMethodID);
gInited = true;
}
return new SkJavaOutputStream(env, stream, storage);
}
+
+static jclass findClassCheck(JNIEnv* env, const char classname[]) {
+ jclass clazz = env->FindClass(classname);
+ SkASSERT(!env->ExceptionCheck());
+ return clazz;
+}
+
+static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
+ const char fieldname[], const char type[]) {
+ jfieldID id = env->GetFieldID(clazz, fieldname, type);
+ SkASSERT(!env->ExceptionCheck());
+ return id;
+}
+
+static jmethodID getMethodIDCheck(JNIEnv* env, jclass clazz,
+ const char methodname[], const char type[]) {
+ jmethodID id = env->GetMethodID(clazz, methodname, type);
+ SkASSERT(!env->ExceptionCheck());
+ return id;
+}
+
+int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env) {
+ jclass inputStream_Clazz = findClassCheck(env, "java/io/InputStream");
+ gInputStream_resetMethodID = getMethodIDCheck(env, inputStream_Clazz, "reset", "()V");
+ gInputStream_markMethodID = getMethodIDCheck(env, inputStream_Clazz, "mark", "(I)V");
+ gInputStream_markSupportedMethodID = getMethodIDCheck(env, inputStream_Clazz, "markSupported", "()Z");
+ gInputStream_readMethodID = getMethodIDCheck(env, inputStream_Clazz, "read", "([BII)I");
+ gInputStream_skipMethodID = getMethodIDCheck(env, inputStream_Clazz, "skip", "(J)J");
+
+ gByteArrayInputStream_Clazz = findClassCheck(env, "java/io/ByteArrayInputStream");
+ // Ref gByteArrayInputStream_Clazz so we can continue to refer to it when
+ // calling IsInstance.
+ gByteArrayInputStream_Clazz = (jclass) env->NewGlobalRef(gByteArrayInputStream_Clazz);
+ gCountField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "count", "I");
+ gPosField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "pos", "I");
+
+ gAssetInputStream_Clazz = findClassCheck(env, "android/content/res/AssetManager$AssetInputStream");
+ // Ref gAssetInputStream_Clazz so we can continue to refer to it when
+ // calling IsInstance.
+ gAssetInputStream_Clazz = (jclass) env->NewGlobalRef(gAssetInputStream_Clazz);
+ gGetAssetIntMethodID = getMethodIDCheck(env, gAssetInputStream_Clazz, "getAssetInt", "()I");
+
+ jclass outputStream_Clazz = findClassCheck(env, "java/io/OutputStream");
+ gOutputStream_writeMethodID = getMethodIDCheck(env, outputStream_Clazz, "write", "([BII)V");
+ gOutputStream_flushMethodID = getMethodIDCheck(env, outputStream_Clazz, "flush", "()V");
+
+ return 0;
+}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index ef5b7c9..1ff0d63 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -414,7 +414,8 @@ static JNIEnv* vm2env(JavaVM* vm)
///////////////////////////////////////////////////////////////////////////////
AndroidPixelRef::AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj,
- SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable, (storageObj == NULL)) {
+ SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable, (storageObj == NULL)),
+ fWrappedPixelRef(NULL) {
SkASSERT(storage);
SkASSERT(env);
@@ -431,8 +432,25 @@ AndroidPixelRef::AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteA
}
+AndroidPixelRef::AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, SkColorTable* ctable) :
+ SkMallocPixelRef(wrappedPixelRef.getAddr(), wrappedPixelRef.getSize(), ctable, false),
+ fWrappedPixelRef(wrappedPixelRef.fWrappedPixelRef ?
+ wrappedPixelRef.fWrappedPixelRef : &wrappedPixelRef)
+{
+ SkASSERT(fWrappedPixelRef);
+ SkSafeRef(fWrappedPixelRef);
+
+ // don't need to initialize these, as all the relevant logic delegates to the wrapped ref
+ fStorageObj = NULL;
+ fHasGlobalRef = false;
+ fGlobalRefCnt = 0;
+ fOnJavaHeap = false;
+}
+
AndroidPixelRef::~AndroidPixelRef() {
- if (fOnJavaHeap) {
+ if (fWrappedPixelRef) {
+ SkSafeUnref(fWrappedPixelRef);
+ } else if (fOnJavaHeap) {
JNIEnv* env = vm2env(fVM);
if (fStorageObj && fHasGlobalRef) {
@@ -441,15 +459,27 @@ AndroidPixelRef::~AndroidPixelRef() {
fStorageObj = NULL;
}
}
+jbyteArray AndroidPixelRef::getStorageObj() {
+ if (fWrappedPixelRef) {
+ return fWrappedPixelRef->fStorageObj;
+ }
+ return fStorageObj;
+}
void AndroidPixelRef::setLocalJNIRef(jbyteArray arr) {
- if (!fHasGlobalRef) {
+ if (fWrappedPixelRef) {
+ // delegate java obj management to the wrapped ref
+ fWrappedPixelRef->setLocalJNIRef(arr);
+ } else if (!fHasGlobalRef) {
fStorageObj = arr;
}
}
void AndroidPixelRef::globalRef(void* localref) {
- if (fOnJavaHeap && sk_atomic_inc(&fGlobalRefCnt) == 0) {
+ if (fWrappedPixelRef) {
+ // delegate java obj management to the wrapped ref
+ fWrappedPixelRef->globalRef(localref);
+ } else if (fOnJavaHeap && sk_atomic_inc(&fGlobalRefCnt) == 0) {
JNIEnv *env = vm2env(fVM);
// If JNI ref was passed, it is always used
@@ -473,7 +503,10 @@ void AndroidPixelRef::globalRef(void* localref) {
}
void AndroidPixelRef::globalUnref() {
- if (fOnJavaHeap && sk_atomic_dec(&fGlobalRefCnt) == 1) {
+ if (fWrappedPixelRef) {
+ // delegate java obj management to the wrapped ref
+ fWrappedPixelRef->globalUnref();
+ } else if (fOnJavaHeap && sk_atomic_dec(&fGlobalRefCnt) == 1) {
JNIEnv *env = vm2env(fVM);
if (!fHasGlobalRef) {
SkDebugf("We don't have a global ref!");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 5a2a6f8..f4590b9 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -91,9 +91,16 @@ public:
AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj,
SkColorTable* ctable);
+ /**
+ * Creates an AndroidPixelRef that wraps (and refs) another to reuse/share
+ * the same storage and java byte array refcounting, yet have a different
+ * color table.
+ */
+ AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, SkColorTable* ctable);
+
virtual ~AndroidPixelRef();
- jbyteArray getStorageObj() { return fStorageObj; }
+ jbyteArray getStorageObj();
void setLocalJNIRef(jbyteArray arr);
@@ -110,6 +117,8 @@ public:
virtual void globalUnref();
private:
+ AndroidPixelRef* const fWrappedPixelRef; // if set, delegate memory management calls to this
+
JavaVM* fVM;
bool fOnJavaHeap; // If true, the memory was allocated on the Java heap
diff --git a/core/res/res/drawable-nodpi/view_accessibility_focused.9.png b/core/res/res/drawable-nodpi/view_accessibility_focused.9.png
deleted file mode 100644
index f03f575..0000000
--- a/core/res/res/drawable-nodpi/view_accessibility_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/view_accessibility_focused.xml b/core/res/res/drawable/view_accessibility_focused.xml
new file mode 100644
index 0000000..0da9a81
--- /dev/null
+++ b/core/res/res/drawable/view_accessibility_focused.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <stroke
+ android:width="2dp"
+ android:color="@color/accessibility_focus_highlight" />
+
+ <corners android:radius="2dp"/>
+
+</shape>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 59749d4..5a693b3 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Laat die houer toe om die opstellingsprogram wat deur die diensverskaffer voorsien word, op te roep. Behoort nooit vir gewone programme nodig te wees nie."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"luister vir waarnemings oor netwerktoestande"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Laat \'n program luister vir waarnemings oor netwerktoestande. Behoort nooit nodig te wees vir normale programme nie."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 8e782a3..8bc211d 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን ያዳምጣል"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"አንድ መተግበሪያ በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን እንዲያዳምጥ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አስፈላጊ ሊሆን አይገባም።"</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ድንቦች አዘጋጅ"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
@@ -964,7 +968,7 @@
<string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"ከ1 ሰከንድ በፊት"</item>
+ <item quantity="one" msgid="4869870056547896011">"ከ1 ሴኮንድ በፊት"</item>
<item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ሰኮንዶች በፊት"</item>
</plurals>
<plurals name="num_minutes_ago">
@@ -985,7 +989,7 @@
<item quantity="other" msgid="2479586466153314633">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"በ1 ሰከንድ"</item>
+ <item quantity="one" msgid="2729745560954905102">"በ1 ሴኮንድ"</item>
<item quantity="other" msgid="1241926116443974687">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
</plurals>
<plurals name="in_num_minutes">
@@ -1001,7 +1005,7 @@
<item quantity="other" msgid="5109449375100953247">"በ<xliff:g id="COUNT">%d</xliff:g> ቀናት"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 ሰከንድ በፊት"</item>
+ <item quantity="one" msgid="1849036840200069118">"1 ሴኮንድ በፊት"</item>
<item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች በፊት"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
@@ -1017,7 +1021,7 @@
<item quantity="other" msgid="3453342639616481191">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"በ1 ሰከንድ"</item>
+ <item quantity="one" msgid="5842225370795066299">"በ1 ሴኮንድ"</item>
<item quantity="other" msgid="5495880108825805108">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
@@ -1041,14 +1045,14 @@
<string name="hours" msgid="894424005266852993">"ሰዓቶች"</string>
<string name="minute" msgid="9148878657703769868">"ደቂቃ"</string>
<string name="minutes" msgid="5646001005827034509">" ደቂቃዎች"</string>
- <string name="second" msgid="3184235808021478">"ሰከንድ"</string>
+ <string name="second" msgid="3184235808021478">"ሴኮንድ"</string>
<string name="seconds" msgid="3161515347216589235">"ሰከንዶች"</string>
<string name="week" msgid="5617961537173061583">"ሳምንት"</string>
<string name="weeks" msgid="6509623834583944518">"ሳምንቶች"</string>
<string name="year" msgid="4001118221013892076">"ዓመት"</string>
<string name="years" msgid="6881577717993213522">"ዓመታት"</string>
<plurals name="duration_seconds">
- <item quantity="one" msgid="6962015528372969481">"1 ሰከንድ"</item>
+ <item quantity="one" msgid="6962015528372969481">"1 ሴኮንድ"</item>
<item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች"</item>
</plurals>
<plurals name="duration_minutes">
@@ -1568,7 +1572,7 @@
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ተትቷል"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"ይዘት መጻፍ ላይ ስህተት"</string>
<string name="reason_unknown" msgid="6048913880184628119">"አይታወቅም"</string>
- <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"አስተዳዳሪ ፒን ያስገቡ"</string>
+ <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"የአስተዳዳሪ ፒን ያስገቡ"</string>
<string name="restr_pin_enter_pin" msgid="3395953421368476103">"ፒን ያስገቡ"</string>
<string name="restr_pin_incorrect" msgid="8571512003955077924">"ትክክል አይደለም"</string>
<string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"የአሁኑ ፒን"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 8988e2e..1dd3b67 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -655,6 +655,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"للسماح للمالك باستدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"الاستماع إلى ملاحظات حول أحوال الشبكة"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"للسماح للتطبيق بالاستماع إلى ملاحظات حول أحوال الشبكة. لا حاجة إلى هذا مع التطبيقات العادية."</string>
+ <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"طلب التعرف على الكلمة المهمة"</string>
+ <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"للسماح للتطبيق بطلب التعرف على الكلمة المهمة. لا حاجة إلى هذا مع التطبيقات العادية."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 839ac38..e29914e 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -655,6 +655,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Sahibinə operator xidmətli tətbiq konfiqurasiyasına müraciət imkanı verir. Normal tətbiqlər üçün tələb olunmamalıdır."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"şəbəkə şəraiti haqqında müşahidələr üçün qulaq asmaq"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tətbiqə şəbəkə şəraiti üzrə müşahidələr üçün qulaq asmaq imkanı verir. Normal tətbiqlər üçün heç vaxt lazım olmamalıdır."</string>
+ <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"isti söz tanınması tələb et"</string>
+ <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Tətbiqə isti söz tanınması tələb etməyə imkan verir. Normal tətbiq üçün lazım ola bilməz."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Parol qaydalarını təyin edin"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açan şifrələrin uzunluğunu və onlardakı icazə verilən işarələrə nəzarət edir."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidi cəhdlərini monitorinq et"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index cc799df..8a1f164 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -680,6 +680,10 @@
<skip />
<!-- no translation found for permdesc_accessNetworkConditions (6899102075825272211) -->
<skip />
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b9cb281..10b9fbb 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Разрешава на притежателя да извиква предоставеното от оператора приложение за конфигуриране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"слушане за наблюдения на мрежовите условия"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Разрешава на приложението да слуша за наблюдения на мрежовите условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4ed0664..c83bd27 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -530,13 +530,13 @@
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directament la configuració del telèfon CDMA"</string>
<string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permet que l\'aplicació iniciï l\'aprovisionament CDMA. Les aplicacions malicioses poden iniciar l\'aprovisionament CDMA innecessàriament."</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar les notificacions d\'actualització de la ubicació"</string>
- <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permet que l\'aplicació activi i desactivi les notificacions d\'actualització de la ubicació de la ràdio. No la poden fer servir les aplicacions normals."</string>
+ <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permet que l\'aplicació activi i desactivi les notificacions d\'actualització de la ubicació del senyal mòbil. No la poden fer servir les aplicacions normals."</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"accedir a les propietats d\'accés"</string>
<string name="permdesc_checkinProperties" msgid="4024526968630194128">"Permet a l\'aplicació l\'accés de lectura/escriptura a les propietats penjades pel servei de registre. No es pot fer servir per a les aplicacions normals."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"triar widgets"</string>
<string name="permdesc_bindGadget" msgid="8261326938599049290">"Permet que l\'aplicació indiqui al sistema quins widgets pot utilitzar cada aplicació. Amb aquest permís, les aplicacions poden concedir accés a les dades personals a altres aplicacions. No indicat per a les aplicacions normals."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar l\'estat del telèfon"</string>
- <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet que l\'aplicació controli les funcions de telèfon del dispositiu. Una aplicació amb aquest permís pot canviar de xarxa, activar i desactivar la ràdio del telèfon i dur a terme accions semblants sense notificar-t\'ho."</string>
+ <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet que l\'aplicació controli les funcions de telèfon del dispositiu. Una aplicació amb aquest permís pot canviar de xarxa, activar i desactivar el senyal mòbil i dur a terme accions semblants sense notificar-t\'ho."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"veure l\'estat i la identitat del telèfon"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet que l\'aplicació accedeixi a les funcions de telèfon del dispositiu. Aquest permís permet que l\'aplicació determini el número de telèfon i els identificadors del dispositiu, si hi ha una trucada activa i el número remot connectat amb una trucada."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evita que la tauleta entri en mode d\'inactivitat"</string>
@@ -593,14 +593,14 @@
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permet que l\'aplicació rebi paquets enviats a tots els dispositius d\'una xarxa Wi-Fi mitjançant les adreces multidifusió, no només a la teva tauleta. Fa servir més energia que el mode que no és multidifusió."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Permet que l\'aplicació rebi paquets enviats a tots els dispositius d\'una xarxa Wi-Fi mitjançant les adreces multidifusió, no només al teu telèfon. Fa servir més energia que el mode que no és multidifusió."</string>
<string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"accés a la configuració de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permet que l\'aplicació configuri la tauleta Bluetooth local i que cerqui i sincronitzi dispositius remots."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permet que l\'aplicació configuri el telèfon Bluetooth local i que cerqui i sincronitzi dispositius remots."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permet que l\'aplicació configuri la tauleta Bluetooth local i que detecti i emparelli dispositius remots."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permet que l\'aplicació configuri el telèfon Bluetooth local i que detecti i emparelli dispositius remots."</string>
<string name="permlab_accessWimaxState" msgid="4195907010610205703">"connecta i desconnecta de WiMAX"</string>
<string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permet que l\'aplicació determini si WiMAX està activat i que vegi la informació sobre totes les xarxes WiMAX que estan connectades."</string>
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Canvia l\'estat de WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet que l\'aplicació connecti i desconnecti la tauleta de les xarxes WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet que l\'aplicació connecti i desconnecti el telèfon de les xarxes WiMAX."</string>
- <string name="permlab_bluetooth" msgid="6127769336339276828">"sincronització amb dispositius Bluetooth"</string>
+ <string name="permlab_bluetooth" msgid="6127769336339276828">"emparella amb dispositius Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet que l\'aplicació visualitzi la configuració de Bluetooth de la tauleta i que estableixi i accepti connexions amb dispositius sincronitzats."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet que una aplicació visualitzi la configuració de Bluetooth del telèfon i que estableixi i accepti connexions amb els dispositius sincronitzats."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controla Near Field Communication (NFC)"</string>
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet que el titular invoqui l\'aplicació de configuració proporcionada per l\'operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"conèixer les observacions sobre les condicions de la xarxa"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet que una aplicació conegui les observacions sobre les condicions de la xarxa. No s\'ha de necessitar mai per a aplicacions normals."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Defineix les normes de contrasenya"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Control d\'intents de desbloqueig de pantalla"</string>
@@ -734,7 +738,7 @@
<string name="phoneTypeIsdn" msgid="8022453193171370337">"XDSI"</string>
<string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string>
<string name="phoneTypeOtherFax" msgid="8587657145072446565">"Altres faxos"</string>
- <string name="phoneTypeRadio" msgid="4093738079908667513">"Ràdio"</string>
+ <string name="phoneTypeRadio" msgid="4093738079908667513">"Senyal mòbil"</string>
<string name="phoneTypeTelex" msgid="3367879952476250512">"Tèlex"</string>
<string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Mòbil de la feina"</string>
@@ -1458,7 +1462,7 @@
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tauleta"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telèfon"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculars"</string>
- <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altaveus del connector"</string>
+ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altaveus de la base"</string>
<string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Àudio per Bluetooth"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index b71ff18..9962533 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje vyvolání konfigurační aplikace poskytnuté operátorem. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"naslouchat informacím o stavu sítě"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikaci naslouchat informacím o stavu sítě. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 7536252..b37c087 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Tillader, at brugeren aktiverer konfigurationsappen, der er forsynet af mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"observer netværksforhold"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillader, at en applikation observerer netværksforhold. Bør aldrig være nødvendigt for almindelige apps."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 2185a42..d489d27 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Inhaber, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Informationen zu den Netzwerkbedingungen erfassen"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ermöglicht der App, Informationen zu den Netzwerkbedingungen zu erfassen. Sollte für normale Apps nie benötigt werden."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9fb21e6..36aff6d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"λήψη παρατηρήσεων σχετικά με την κατάσταση δικτύου"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Επιτρέπει σε μια εφαρμογή να λαμβάνει παρατηρήσεις σχετικά με την κατάσταση δικτύου. Δεν θα πρέπει να απαιτείται ποτέ για κανονικές εφαρμογές."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 936062b..3db3116 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 936062b..3db3116 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index b91438d..0271bc8 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite al propietario ejecutar la aplicación de configuración proporcionada por el proveedor. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Detectar cambios en el estado de la red"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -1581,7 +1585,7 @@
<item quantity="one" msgid="311050995198548675">"Intentar en 1 s"</item>
<item quantity="other" msgid="4730868920742952817">"Intentar en <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
- <string name="restr_pin_try_later" msgid="973144472490532377">"Volver a intentar más tarde"</string>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"Vuelve a intentar más tarde."</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Desliza el borde para ver la barra."</string>
<string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Desliza el dedo desde el borde de la pantalla para mostrar la barra del sistema."</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 620410e..820ea10 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar cambios en el estado de la red"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. No debe ser necesario para aplicaciones normales."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
@@ -1568,9 +1572,9 @@
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelado"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error al escribir contenido"</string>
<string name="reason_unknown" msgid="6048913880184628119">"desconocido"</string>
- <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"Introducir PIN de administrador"</string>
+ <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"Introduce el PIN del administrador"</string>
<string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introducir PIN"</string>
- <string name="restr_pin_incorrect" msgid="8571512003955077924">"Incorrecta"</string>
+ <string name="restr_pin_incorrect" msgid="8571512003955077924">"Incorrecto"</string>
<string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN actual"</string>
<string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN nuevo"</string>
<string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirma tu nuevo PIN"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index a74334d..6ea84f3 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lubab omanikul aktiveerida operaatoripoolse konfiguratsioonirakenduse. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"võrgutingimuste teabe kuulamine"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lubab rakendusel kuulata võrgutingimuste teavet. Ei ole kunagi vajalik tavaliste rakenduste puhul."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 0193475..4e60309 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"به دارنده اجازه می‌دهد که تنظیمات برنامه شرکت مخابراتی را لغو کند. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"گوش دادن برای بررسی شرایط شبکه"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"به برنامه امکان می‌دهد برای بررسی شرایط شبکه گوش دهد. این امکان هرگز نباید برای برنامه‌های معمولی مورد نیاز باشد."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسه‎های مجاز در گذرواژه‌های بازکردن قفل صفحه را کنترل کنید."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index dbd77e0..94a1aeb 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Antaa luvanhaltijan käynnistää palveluntarjoajan määrityssovelluksen. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"verkon tilahavaintojen kuunteleminen"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Antaa sovellukselle luvan kuunnella verkon tilahavaintoja. Ei tavallisten sovellusten käyttöön."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 47df2d0..9c4ee14 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par le fournisseur de services. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter les observations sur les conditions du réseau. Ne devrait jamais être nécessaire pour les applications standards."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -1578,8 +1582,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Les NIP ne correspondent pas. Essayez à nouveau."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"Le NIP est trop court. Il doit comporter au moins 4 chiffres."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Dans 1 seconde"</item>
- <item quantity="other" msgid="4730868920742952817">"Dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one" msgid="311050995198548675">"Réessayer dans 1 s"</item>
+ <item quantity="other" msgid="4730868920742952817">"Réessayer dans <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Réessayez plus tard"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Gliss. doigt sur côté écr. aff. barre"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d639f49..e841125 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par l\'opérateur. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter des observations sur les conditions du réseau. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -1578,8 +1582,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Les codes PIN ne correspondent pas. Veuillez réessayer."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"Le code PIN est trop court. Il doit comporter au moins 4 chiffres."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Essay. dans 1 s"</item>
- <item quantity="other" msgid="4730868920742952817">"Essay. dans <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ <item quantity="one" msgid="311050995198548675">"Réessayer dans 1 s"</item>
+ <item quantity="other" msgid="4730868920742952817">"Réessayer dans <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Veuillez réessayer ultérieurement."</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Faire glisser côté pour voir barre."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 9f4927b..a1a311f 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -374,7 +374,7 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्‍यवस्‍थापक के साथ सहभागिता करें"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्‍यवस्‍थापक को उद्देश्य भेजने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
- <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण व्यवस्थापक को जोड़ें या निकालें"</string>
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण उपकरण सुचारू ढ़ंग से चलाने वाले को जोड़ें या निकालें"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"धारक को सक्रिय डिवाइस व्यवस्थापकों को जोड़ने या निकालने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"स्‍क्रीन अभिविन्‍यास बदलें"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"एप्‍लिकेशन को किसी भी समय स्‍क्रीन का रोटेशन बदलने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
@@ -453,9 +453,9 @@
<string name="permlab_readCalendar" msgid="5972727560257612398">"केलैंडर ईवेंट के साथ-साथ गोपनीय जानकारी पढ़ें"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"एप्लिकेशन को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, एप्लिकेशन आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
<string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"एप्लिकेशन को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, एप्लिकेशन आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
- <string name="permlab_writeCalendar" msgid="8438874755193825647">"स्‍वामी की जानकारी के बि‍ना कैलेंडर ईवेंट जोड़ें या संशोधि‍त करें और अति‍थि‍यों को ईमेल भेजें"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"एप्लिकेशन को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने टेबलेट पर संशोधित कर सकते हैं. इससे एप्लिकेशन, स्‍वामी की जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"एप्लिकेशन को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने फ़ोन पर संशोधित कर सकते हैं. इससे एप्लिकेशन, स्‍वामी की जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
+ <string name="permlab_writeCalendar" msgid="8438874755193825647">"अपनी जानकारी के बि‍ना कैलेंडर ईवेंट जोड़ें या संशोधि‍त करें और अति‍थि‍यों को ईमेल भेजें"</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"एप्लिकेशन को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने टेबलेट पर संशोधित कर सकते हैं. इससे एप्लिकेशन,अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"एप्लिकेशन को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने फ़ोन पर संशोधित कर सकते हैं. इससे एप्लिकेशन, अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
<string name="permlab_accessMockLocation" msgid="8688334974036823330">"परीक्षण के लिए नकली स्‍थान स्रोत"</string>
<string name="permdesc_accessMockLocation" msgid="5808711039482051824">"परीक्षण के लिए कृत्रिम स्थान स्रोत बनाएं या एक नया स्थान प्रदाता इंस्‍टॉल करें. यह एप्लिकेशन को स्‍थान और/या अन्‍य स्थान स्रोतों जैसे GPS या स्‍थान प्रदाताओं द्वारा लौटाई गई स्थिति को ओवरराइड करने देता है."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"अतिरिक्त स्‍थान प्रदाता आदेशों में पहुंचे"</string>
@@ -617,10 +617,10 @@
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"एप्‍लिकेशन को वर्तमान में समन्वयित फ़ीड के बारे में विवरण प्राप्त करने देता है."</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"ग्राहकी-प्राप्त फ़ीड लिखें"</string>
<string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"एप्लिकेशन को आपके वर्तमान समन्वयित फ़ीड को संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके समन्वयित फ़ीड को बदल सकते है."</string>
- <string name="permlab_readDictionary" msgid="4107101525746035718">"डिक्शनरी में आपके द्वारा जोड़े गए शब्‍दों को पढ़ें"</string>
- <string name="permdesc_readDictionary" msgid="659614600338904243">"एप्‍लिकेशन को ऐसे सभी शब्‍दों, नामों और वाक्यांशों को पढ़ने देता है जो संभवत: उपयोगकर्ता द्वारा उपयोगकर्ता ‍डिक्शनरी में संग्रहीत किए गए हों."</string>
- <string name="permlab_writeDictionary" msgid="2183110402314441106">"उपयोगकर्ता द्वारा परिभाषित डिक्शनरी में शब्द जोड़ें"</string>
- <string name="permdesc_writeDictionary" msgid="8185385716255065291">"एप्लिकेशन को उपयोगकर्ता डिक्शनरी में नए शब्द लिखने देता है."</string>
+ <string name="permlab_readDictionary" msgid="4107101525746035718">"शब्दकोश में आपके द्वारा जोड़े गए शब्‍दों को पढ़ें"</string>
+ <string name="permdesc_readDictionary" msgid="659614600338904243">"एप्‍लिकेशन को ऐसे सभी शब्‍दों, नामों और वाक्यांशों को पढ़ने देता है जो संभवत: उपयोगकर्ता द्वारा उपयोगकर्ता ‍शब्दकोश में संग्रहीत किए गए हों."</string>
+ <string name="permlab_writeDictionary" msgid="2183110402314441106">"उपयोगकर्ता द्वारा परिभाषित शब्दकोश में शब्द जोड़ें"</string>
+ <string name="permdesc_writeDictionary" msgid="8185385716255065291">"एप्लिकेशन को उपयोगकर्ता शब्दकोश में नए शब्द लिखने देता है."</string>
<string name="permlab_sdcardRead" product="nosdcard" msgid="8235341515605559677">"संरक्ष‍ित संग्रहण पर पहुंच का परीक्षण करें"</string>
<string name="permlab_sdcardRead" product="default" msgid="8235341515605559677">"संरक्ष‍ित संग्रहण पर पहुंच का परीक्षण करें"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3642473292348132072">"एप्लि. को USB संग्रहण अनुमति का परीक्षण करने देता है जो भविष्‍य के उपकरणों में उपलब्‍ध होगा."</string>
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्लिकेशन प्रारंभ करने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"नेटवर्क स्थितियों के अवलोकनों को सुनें"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"एप्लिकेशन को नेटवर्क स्थितियों के अवलोकनों को सुनने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"स्‍क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"स्‍क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
@@ -804,7 +808,7 @@
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"स्‍क्रीन लॉक की गई है."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"अनलॉक करने के लिए मेनू दबाएं या आपातलकालीन कॉल करें."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"अनलॉक करने के लिए मेनू दबाएं."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"अनलॉक करने के लिए प्रतिमान आरेखित करें"</string>
+ <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"अनलॉक करने के लिए आकार आरेखित करें"</string>
<string name="lockscreen_emergency_call" msgid="5347633784401285225">"आपातकालीन कॉल"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"कॉल पर वापस लौटें"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"सही!"</string>
@@ -833,19 +837,19 @@
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"कृपया उपयोगकर्ता मार्गदर्शिका देखें या ग्राहक सहायता से संपर्क करें."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"सिम कार्ड लॉक किया गया है."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"सिम कार्ड अनलॉक कर रहा है…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपने अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिखा है. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"आपने अपना पिन <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिखा है. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुनः प्रयास करें."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके टेबलेट को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके फ़ोन को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके टेबलेट को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत बनाया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने Google साइन-इन का उपयोग करके आपके फ़ोन को अनलॉक करने को कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"आप गलत तरीके से टेबलेट को अनलॉक करने का प्रयास <xliff:g id="NUMBER_0">%d</xliff:g> बार कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयास के बाद, टेबलेट फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"आप गलत तरीके से फ़ोन को अनलॉक करने का प्रयास <xliff:g id="NUMBER_0">%d</xliff:g> बार कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयास के बाद, फ़ोन फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"आप टेबलेट को गलत तरीके से <xliff:g id="NUMBER">%d</xliff:g> बार अनलॉक करने का प्रयास कर चुके हैं. टेबलेट अब फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"आप फ़ोन को गलत तरीके से <xliff:g id="NUMBER">%d</xliff:g> बार अनलॉक करने का प्रयास कर चुके हैं. फ़ोन अब फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"प्रतिमान भूल गए?"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"आकार भूल गए?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"खाता अनलॉक"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"बहुत अधिक प्रतिमान प्रयास"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"बहुत अधिक आकार प्रयास"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"अनलॉक करने के लिए, अपने Google खाते से प्रवेश करें."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"उपयोगकर्ता नाम (ईमेल)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"पासवर्ड"</string>
@@ -856,10 +860,10 @@
<string name="lockscreen_unlock_label" msgid="737440483220667054">"अनलॉक करें"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"ध्‍वनि चालू करें"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"ध्वनि बंद"</string>
- <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"प्रतिमान प्रारंभ किया गया"</string>
- <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"प्रतिमान साफ़ किया गया"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"आकार प्रारंभ किया गया"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"आकार साफ़ किया गया"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"कक्ष जोड़ा गया"</string>
- <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"प्रतिमान पूरा किया गया"</string>
+ <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"आकार पूरा किया गया"</string>
<string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d विजेट में से %2$d."</string>
<string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"विजेट जोड़ें"</string>
<string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"रिक्त"</string>
@@ -875,11 +879,11 @@
<string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"विजेट <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> को हटा दिया गया."</string>
<string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"अनलॉक क्षेत्र विस्तृत करें."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"स्लाइड अनलॉक."</string>
- <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"प्रतिमान अनलॉक."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"आकार अनलॉक."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"फेस अनलॉक."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"पिन अनलॉक."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"पासवर्ड अनलॉक."</string>
- <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"प्रतिमान क्षेत्र."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"आकार क्षेत्र."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"स्लाइड क्षेत्र."</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
@@ -1479,12 +1483,12 @@
<string name="wifi_display_notification_message" msgid="4498802012464170685">"यह स्क्रीन अन्य उपकरण पर दिखाई दे रही है"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"डिस्कनेक्ट करें"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"आपातकालीन कॉल"</string>
- <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"प्रतिमान भूल गए"</string>
- <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत प्रतिमान"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"आकार भूल गए"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत आकार"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"गलत पासवर्ड"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"गलत PIN"</string>
<string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना प्रतिमान आरेखित करें"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना आकार आरेखित करें"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम PIN डालें"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"PIN डालें"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"पासवर्ड डालें"</string>
@@ -1497,7 +1501,7 @@
<string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK कोड 8 या अधिक संख्या वाला होना चाहिए."</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड का मिलान नहीं होता"</string>
- <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक प्रतिमान प्रयास"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक आकार प्रयास"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से प्रवेश करें."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"उपयोगकर्ता नाम (ईमेल)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
@@ -1507,13 +1511,13 @@
<string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जांच की जा रही है…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"आप टेबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, टेबलेट फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, फ़ोन फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"आप टेबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. टेबलेट अब फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. फ़ोन अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"निकालें"</string>
<string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"वॉल्यूम को उपरोक्त अनुशंसित स्तर तक बढ़ाएं?\nलंबे समय तक अधिक वॉल्यूम पर सुनने से आपकी सुनने की क्षमता को क्षति पहुंच सकती है."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index cd43b8d..cfac520 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Dopušta nositelju pozivanje operaterove aplikacije za konfiguraciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"praćenje motrenja mrežnih uvjeta"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Omogućuje aplikaciji praćenje motrenja mrežnih uvjeta. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 437367f..28a4317 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lehetővé teszi a használó számára a szolgáltató által biztosított konfigurációs alkalmazás hívását. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"hálózati körülményekkel kapcsolatos észrevételek figyelemmel kísérése"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lehetővé teszi egy alkalmazás számára, hogy figyelemmel kísérje a hálózati körülményekkel kapcsolatos észrevételeket. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index b15ea4f..c6c484b 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Թույլ է տալիս սեփականատիրոջը գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"լսել դիտարկումներ ցանցային պայմանների վերաբերյալ"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Հավելվածին թույլ է տալիս լսել դիտարկումներ ցանցային պայմանների վերաբերյալ: Սովորական հավելվածների համար երբեք պետք չի գալիս:"</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Սահմանել գաղտնաբառի կանոնները"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Վերահսկել էկրանի ապակողպման գաղտնաբառերի թույլատրելի երկարությունն ու գրանշանները:"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Վերահսկել էկրանի ապակողպման փորձերը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 04110af..cd2fc6b 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Memungkinkan pemegang meminta aplikasi konfigurasi yang disediakan operator. Tidak pernah diperlukan aplikasi normal."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"mendengar untuk observasi kondisi jaringan"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Memungkinkan aplikasi mendengar untuk observasi kondisi jaringan. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index fd864da..3bf8401 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascolto delle osservazioni sulle condizioni di rete"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Consente a un\'applicazione di ascoltare le osservazioni sulle condizioni di rete. Da non utilizzare mai con app normali."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Imposta regole password"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitora tentativi di sblocco dello schermo"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 1875122..aa3d410 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -655,6 +655,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ההרשאה הזו מאפשרת לבעלים להפעיל את אפליקציית התצורה שסופקה על ידי ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"קליטת מעקב אחר תנאי רשת"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"מאפשרת לאפליקציה לקלוט מעקב אחר תנאי רשת. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
+ <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"בקשה של הכרה במילת הפעלה"</string>
+ <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"מאפשרת לאפליקציה לבקש הכרה במילת הפעלה. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index bf2dcac..28bc0d8 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"携帯通信会社が提供する設定アプリを呼び出すことを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ネットワーク状況監視のためのリッスン"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ネットワーク状況を監視するためリッスンすることをアプリに許可します。通常のアプリで必要になることはありません。"</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 745b4c7..b9a7946 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"საშუალებას აძლევს მფლობელს გამოიწვიოს ოპერატორის მიერ მოწოდებული კონფიგურაციის აპი. ჩვეულებრივ აპს ეს წესით არასოდეს არ უნდა დაჭირდეს."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"განხორციელდეს ქსელის მდგომარეობის მონიტორინგი"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"საშუალებას აძლევს აპლიკაციებს განახორციელოს ქსელის მდგომარეობის მონიტორინგი. ეს ფუნქცია ჩვეულებრივ აპებს არ ჭირდება."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"პაროლის წესების დაყენება"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"გააკონტროლეთ ეკრანის განბლოკვის პაროლში დაშვებული სიმბოლოები და მისი სიგრძე."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ეკრანის განბლოკვის მცდელობების გაკონტროლება"</string>
@@ -1122,7 +1126,7 @@
<string name="smv_application" msgid="3307209192155442829">"აპმა <xliff:g id="APPLICATION">%1$s</xliff:g> (პროცესი <xliff:g id="PROCESS">%2$s</xliff:g>) დაარღვია საკუთარი StrictMode დებულება."</string>
<string name="smv_process" msgid="5120397012047462446">"ამ პროცესმა <xliff:g id="PROCESS">%1$s</xliff:g> დააზიანა საკუთარი StrictMode დებულება."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android ახალ ვერსიაზე გადადის…"</string>
- <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g> აპლიკაციის (სულ <xliff:g id="NUMBER_1">%2$d</xliff:g>-დან) ოპტიმიზაცია."</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"მიმდინარეობს აპლიკაციების ოპტიმიზაცია. დასრულებულია <xliff:g id="NUMBER_0">%1$d</xliff:g>, სულ <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"აპების ჩართვა"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"ჩატვირთვის დასასრული."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index a75c6a9..4362bdc 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -655,6 +655,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ដក​ហូត​កម្មវិធី​កំណត់​រចនាសម្ព័ន្ធ​ដែល​បាន​ផ្ដល់​ដោយ​ក្រុមហ៊ុន​បញ្ជូន។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"សង្កេត​មើល​លើ​លក្ខខណ្ឌ​បណ្ដាញ"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ឲ្យ​កម្មវិធី​សង្កេត​មើល​​លើ​លក្ខខណ្ឌ​បណ្ដាញ​។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
+ <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"ស្នើ​ការ​ស្គាល់ hotword"</string>
+ <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"ឲ្យ​កម្មវិធី​ស្នើ​ការ​ស្គាល់ hotword ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"កំណត់​ក្បួន​ពាក្យ​សម្ងាត់"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"ពិនិត្យ​ប្រវែង និង​តួអក្សរ​ដែល​បាន​អនុញ្ញាត​ក្នុង​ពាក្យ​សម្ងាត់​ចាក់​សោ​អេក្រង់។"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ពិនិត្យ​ការ​ព្យាយាម​ដោះ​សោ​អេក្រង់"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 9f6c84b..69b74e3 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"권한을 가진 프로그램이 이동통신사에서 제공한 구성 앱을 호출하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"네트워크 상태에 대한 관측 보고 수신"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"애플리케이션이 네트워크 상태에 대한 관측 보고를 수신하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 0dddde7..cb71e31 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ອະ​ນຸ​ຍາດ​ໃຫ້​ເຈົ້າຂອງຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ. ບໍ່ໜ້າຈະຕ້ອງການສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັ່ນຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ. ປົກກະຕິແລ້ວແອັບຯທຳມະດາຈະບໍ່ຕ້ອງການໃຊ້."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"ຕັ້ງຄ່າກົດຂອງລະຫັດຜ່ານ"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"ຄວບຄຸມຄວາມຍາວຂອງໂຕອັກສອນທີ່ສາມາດໃຊ້ກັບລະຫັດປົດລັອກໜ້າຈໍ"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ຕິດຕາມການພະຍາຍາມປົດລັອກໜ້າຈໍ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9fa2070..fc4fcc2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Turėtojui leidžiama iškviesti operatoriaus pateiktą konfigūravimo programą. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"vykdyti tinklo sąlygų stebėjimą"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Leidžiama programai vykdyti tinklo sąlygų stebėjimą. To niekada neturėtų prireikti naudojant įprastas programas."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5d81fc7..beff99fd 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ļauj īpašniekam izsaukt operatora nodrošināto konfigurācijas lietotni. Parastām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"iegūt informāciju par tīkla stāvokļa novērojumiem"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ļauj lietojumprogrammai iegūt informāciju par tīkla stāvokļa novērojumiem. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 3fe7899..16ba5f5 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -655,6 +655,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Эзэмшигчид үүрэн компанийн нийлүүлсэн тохируулах апп-г өдөөх боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Сүлжээний байдлын талаар ажиглалтуудыг хүлээн авах"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Аппликешнд сүлжээний байдлын талаар ажиглалтуудыг хүлээн авахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
+ <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"хотворд таних хүсэлт"</string>
+ <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Аппликешнд хотворд таних хүсэлт гаргахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Нууц үгний дүрмийг тохируулах"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Дэлгэц түгжих нууц үгэнд зөвшөөрөгдсөн тэмдэгт болон уртыг удирдах"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Дэлгэц тайлах оролдлогыг хянах"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 748fc5a..d422e32 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Membenarkan pemegang menggunakan apl konfigurasi yang diberikan oleh pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"dengar pemerhatian mengenai keadaan rangkaian"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Membenarkan aplikasi mendengar pemerhatian tentang keadaan rangkaian. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
@@ -1578,8 +1582,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN tidak sepadan. Cuba lagi."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN terlalu pendek. Mesti sekurang-kurangnya 4 angka."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Cuba lg dlm 1 st"</item>
- <item quantity="other" msgid="4730868920742952817">"Cuba lg dlm <xliff:g id="COUNT">%d</xliff:g> st"</item>
+ <item quantity="one" msgid="311050995198548675">"Cuba 1 saat lagi"</item>
+ <item quantity="other" msgid="4730868920742952817">"Cuba <xliff:g id="COUNT">%d</xliff:g> saat lagi"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Cuba sebentar lagi"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Leret bhg tepi skrin utk serlah bar"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f53f817..5468779 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Gir innehaveren tillatelse til å kalle opp den konfigurasjonsappen som ble levert av operatøren. Dette skal ikke være nødvendig for vanlige apper."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lytte etter observasjoner om nettverksforhold"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Gir appen tillatelse til å lytte etter observasjoner om nettverksforhold. Dette skal ikke være nødvendig for vanlige apper."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 67775da..10f8376 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"प्रयोगकर्तालाई वाहक-प्रदान विन्यास अनुप्रयोग सुरु गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूलाई कहिल्यै आवश्यक पर्ने छैन।"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"सञ्जाल अवस्थाका पर्यवेक्षणका लागि सुन्नुहोस्"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"सञ्जाल अवस्थाका पर्यवेक्षण सुन्नका लागि अनुप्रयोगलाई अनुमति दिन्छ।सामान्य अनुप्रयोगलाई चाँहिदै नचाँहिन सक्छ।"</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियमहरू मिलाउनुहोस्"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रिन-अनलक पासवर्डहरूमा अनुमति दिइएको लम्बाइ र अक्षरहरू नियन्त्रण गर्नुहोस्।"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"मोनिटर स्क्रिन-अनलक प्रयत्नहरू"</string>
@@ -1568,7 +1572,7 @@
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"रद्द गरियो"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"सामाग्री लेखनमा त्रुटि"</string>
<string name="reason_unknown" msgid="6048913880184628119">"अज्ञात"</string>
- <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"प्रशासक PIN प्रविष्ट गर्नुहोस्"</string>
+ <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"प्रशासक PIN प्रविष्टि गर्नुहोस्"</string>
<string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN प्रविष्टि गर्नुहोस्"</string>
<string name="restr_pin_incorrect" msgid="8571512003955077924">"गलत"</string>
<string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"वर्तमान PIN"</string>
@@ -1578,10 +1582,10 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN हरू मेल खाएनन्। पुनः प्रयास गर्नुहोस्।"</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN अति छोटो भयो। कम्तीमा ४ अङ्क हुन आवश्यक छ।"</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"१ सेकेन्ड पछि पुन: प्रयास गर्नुहोला।"</item>
- <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा पुन: प्रयास गर्नुहोस्"</item>
+ <item quantity="one" msgid="311050995198548675">"१ सेकेन्ड पछि पुनः प्रयास गर्नुहोस्।"</item>
+ <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा पुनः प्रयास गर्नुहोस्"</item>
</plurals>
- <string name="restr_pin_try_later" msgid="973144472490532377">"पछि पुन: प्रयास गर्नुहोस्"</string>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"पछि पुनः प्रयास गर्नुहोस्"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"पट्टि देखिने बनाउन स्क्रिनको छेउमा स्वाइप गर्नुहोस्"</string>
<string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"प्रणाली पट्टि देखिने बनाउन स्क्रिनको छेउबाट स्वाइप गर्नुहोस्"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index db0c218..f4234da 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Hiermee kan de houder de door de provider geleverde configuratie-app aanroepen. Nooit vereist voor normale apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"controleren op waarnemingen met betrekking tot netwerkomstandigheden"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Hiermee kan een app controleren op waarnemingen met betrekking tot netwerkomstandigheden. Nooit vereist voor normale apps."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d2cf5b8..6c01e1c 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Zezwala na wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"śledź stan sieci"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Pozwala aplikacji śledzić stan sieci. Nieprzeznaczone dla zwykłych aplikacji."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index a21994b..31b7e25 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o titular invoque a aplicação de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ouvir observações sobre as condições da rede"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que uma aplicação ouça observações sobre as condições da rede. Nunca deverá ser necessário para aplicações normais."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1189c2a..ee765d5 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o proprietário invoque o aplicativo de configuração fornecido pela operadora. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar observações nas condições da rede"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que o aplicativo detecte observações nas condições da rede. Não deve ser necessário para aplicativos comuns."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controle o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 68f0e06..f57f821 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1108,6 +1108,10 @@
<skip />
<!-- no translation found for permdesc_accessNetworkConditions (6899102075825272211) -->
<skip />
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<!-- no translation found for policylab_limitPassword (4497420728857585791) -->
<skip />
<!-- no translation found for policydesc_limitPassword (3252114203919510394) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0e7ba3a..a2ec3d0 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite proprietarului să apeleze aplicația de configurare furnizată de operator. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascultă observații despre starea rețelei"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite unei aplicații să asculte observații despre starea rețelei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 80e806f..7e6645d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Владелец сможет запускать приложение настроек, предоставленное оператором. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Использование данных о состоянии сети"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Приложение сможет использовать данные о состоянии сети. Это разрешение обычно используется только специальными приложениями."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 9b32bd9..2ec8370 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"වාහකයා ලබාදුන් සැකසුම් යෙදුම් උත්පාදනයට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම් සඳහා කිසිදා අවශ්‍ය නොවෙයි."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ජාල තත්ව මත නිරීක්ෂණ වෙත ඇහුම්කන් දීම"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"යෙදුමකට ජාල තත්ව මත නිරීක්ෂණ වෙත ඇහුම්කන් දීමට අවසර දේ. සාමාන්‍ය යෙදුම් සඳහා කිසිදා අවශ්‍ය නොවේ."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"මුරපද නීති සකස් කිරීම"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"තිරය අගුළු ඇරීමේ මුරපදයට අනුමත අකුරු සහ දිග පාලනය කරන්න."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"තිරය අගුළු ඇරීමේ උත්සාහයන් නිරීක්ෂණය කරන්න"</string>
@@ -1581,7 +1585,7 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN නොගැළපෙයි. නැවත උත්සහ කරන්න."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN කුඩා වැඩිය. ඉලක්කම් 4 වත් විය යුතුය."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"තවත් තත්පර ^1 කින් යළි උත්සාහ කරන්න"</item>
+ <item quantity="one" msgid="311050995198548675">"තවත් තත්පර 1 කින් යළි උත්සාහ කරන්න"</item>
<item quantity="other" msgid="4730868920742952817">"තත්පර <xliff:g id="COUNT">%d</xliff:g> කින් නැවත උත්සහ කරන්න"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"පසුව නැවත උත්සාහ කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index ea118ce..b8f13a2 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje držiteľovi vyvolať aplikáciu pre konfiguráciu poskytnutú operátorom. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"zachytávať informácie o stave siete"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikácii zachytávať informácie o stave siete. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
@@ -1578,8 +1582,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN sa nezhodujú. Skúste to znova."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je príliš krátky. Musí mať minimálne 4 číslice."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Skúste to znova o 1 s."</item>
- <item quantity="other" msgid="4730868920742952817">"Skúste to znova o <xliff:g id="COUNT">%d</xliff:g> s."</item>
+ <item quantity="one" msgid="311050995198548675">"Skúste to zas o 1 s"</item>
+ <item quantity="other" msgid="4730868920742952817">"Skúste to zas o <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Skúste to znova neskôr"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Panel zobraz. prejdením okraja obr."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a58e474..191b438 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lastniku omogoča sproženje operaterjeve aplikacije za konfiguracijo. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"spremljanje razmer v omrežju"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Aplikaciji omogoča spremljanje razmer v omrežju. Pri navadnih aplikacijah to ne bi smelo biti potrebno."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index ce4e284..1c6f893 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозвољава власнику да позива апликацију са конфигурацијом коју одређује оператер. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"праћење података о условима на мрежи"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозвољава апликацији да прати податке о условима на мрежи. Не би никада требало да буде потребно за нормалне апликације."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 2ea2b0a..01d2b15 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Innehavaren tillåts att anropa konfigurationsappen från operatören. Ska inte behövas för vanliga appar."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lyssna efter information om nätverksförhållanden"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillåter att appen lyssnar efter information om nätverksförhållanden. Vanliga appar bör aldrig behöva den här behörigheten."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 2d18ed7..00e208b 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Inaruhusu kishikiliaji kuomba programu ya usakinishaji inayotolewa na mto huduma. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"sikiliza matukio katika hali za mtandao"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Huruhusu programu kusikiliza matukio katika hali za mtandao. Haipaswi kuhitajika kamwe kwa programu za kawaida."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Weka kanuni za nenosiri"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Dhibiti urefu na vibambo vinavyoruhusiwa katika manenosiri ya kufungua skrini."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Chunguza majaribio ya kutofun gua skrini"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 226b48d..d2f3343 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"อนุญาตให้ผู้ใช้สามารถเรียกใช้แอปการกำหนดค่าของผู้ให้บริการ ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"อนุญาตให้แอปพลิเคชันฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย ไม่จำเป็นสำหรับแอปปกติ"</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 36a3ffe..fbe1d0a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Nagbibigay-daan sa may-ari na paganahin ang app ng configuration na ibinigay ng carrier. Hindi dapat kailanganin para sa normal na apps kahit kailan."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"makinig sa mga obserbasyon sa mga kundisyon ng network"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Nagbibigay-daan sa isang application na makinig sa mga obserbasyon sa mga kundisyon ng network. Dapat na hindi kailanman kakailanganin para sa normal na apps."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8fb697d..43cffc0 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"İzin sahibine, operatör tarafından sağlanan yapılandırma uygulamasını çalıştırma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ağ koşullarındaki gözlemleri dinle"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Bir uygulamaya, ağ koşullarındaki gözlemleri dinleme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 9412629..db91e1e 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозволяє власнику викликати надану оператором програму конфігурації. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"прослуховувати дані спостережень за станом мережі"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозволяє програмі прослуховувати дані спостережень за станом мережі. Ніколи не застосовується для звичайних програм."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
@@ -1578,8 +1582,8 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-коди не збігаються. Повторіть спробу."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код закороткий. Має бути принаймні 4 цифри."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="311050995198548675">"Спробуйте за 1 с"</item>
- <item quantity="other" msgid="4730868920742952817">"Спробуйте за <xliff:g id="COUNT">%d</xliff:g> с"</item>
+ <item quantity="one" msgid="311050995198548675">"Повтор за 1 с"</item>
+ <item quantity="other" msgid="4730868920742952817">"Повтор за <xliff:g id="COUNT">%d</xliff:g> с"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Спробуйте пізніше"</string>
<string name="transient_navigation_confirmation" msgid="4907844043611123426">"Гортайте від краю, щоб відкрити панель"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 4e44cc4..2c6888e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Cho phép chủ sở hữu gọi ra ứng dụng cấu hình do nhà cung cấp dịch vụ cung cấp. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"quan sát các điều kiện mạng"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Cho phép ứng dụng quan sát các điều kiện mạng. Không bao giờ cần cho ứng dụng thông thường."</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kiểm soát độ dài và ký tự được phép trong mật khẩu mở khóa màn hình."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 895952a..d7637ac 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允许应用调用运营商提供的配置应用。普通应用绝不需要此权限。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"监听网络状况的观测信息"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允许应用监听网络状况的观测信息。普通应用绝不需要此权限。"</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 7a2298f..42fec0d 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式調用流動網絡供應商提供的設定應用程式 (不建議一般應用程式使用)。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽對網絡狀況的觀察"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽對網絡狀況的觀察 (不建議一般應用程式使用)。"</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解鎖密碼所允許的長度和字元。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"監控屏幕解鎖嘗試次數"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index df6da73..7b25629 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -655,6 +655,10 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式叫用行動通訊業者提供的設定應用程式 (一般應用程式並不需要)。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽網路狀況觀察資訊"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽網路狀況觀察資訊 (一般應用程式並不需要)。"</string>
+ <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
+ <skip />
+ <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
+ <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index dd8a7b9..e32ef9f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -655,6 +655,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ivumela umnikazi ukuthi abuyisele uhlelo lokusebenza lokulungiselelwa. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Lalela okubonwayo kuzimo zenethiwekhi"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ivumela uhlelo lokusebenza ukuthi lulalele okubonwa kuzimo zenethiwekhi. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
+ <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"cela ukubonwa kwe-hotword"</string>
+ <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Ivumela uhlelo lokusebenza ukuthi lucele ukubonwa kwe-hotword. Akumele ifunelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a47e518..7ddf2e9 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6128,8 +6128,4 @@
<attr name="textView" format="reference" />
</declare-styleable>
- <declare-styleable name="DocumentsProviderInfo">
- <attr name="customRoots" format="boolean" />
- </declare-styleable>
-
</resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 604bf4b..284f613 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -195,5 +195,7 @@
<color name="keyguard_avatar_frame_shadow_color">#80000000</color>
<color name="keyguard_avatar_nick_color">#ffffffff</color>
<color name="keyguard_avatar_frame_pressed_color">#ff35b5e5</color>
+
+ <color name="accessibility_focus_highlight">#80ffff00</color>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6c3856e..1b4a083 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2073,7 +2073,6 @@
<public type="attr" name="vendor" />
<public type="attr" name="category" />
<public type="attr" name="isAsciiCapable" />
- <public type="attr" name="customRoots" />
<public type="attr" name="autoMirrored" />
<public type="attr" name="supportsSwitchingToNextInputMethod" />
<public type="attr" name="requireDeviceUnlock" />
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 54881d5..7e0202e 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -16,8 +16,7 @@
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.connectivitymanagertest"
- android:sharedUserId="android.uid.system">
+ package="com.android.connectivitymanagertest">
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/core/tests/coretests/src/android/database/MatrixCursorTest.java b/core/tests/coretests/src/android/database/MatrixCursorTest.java
index fc48c17..aa805dc 100644
--- a/core/tests/coretests/src/android/database/MatrixCursorTest.java
+++ b/core/tests/coretests/src/android/database/MatrixCursorTest.java
@@ -132,18 +132,18 @@ public class MatrixCursorTest extends TestCase {
MatrixCursor cursor = newMatrixCursor();
cursor.newRow()
- .offer("float", 4.2f)
- .offer("string", "foobar")
- .offer("blob", new byte[] {(byte) 0xaa, (byte) 0x55})
- .offer("lolwat", "kittens");
+ .add("float", 4.2f)
+ .add("string", "foobar")
+ .add("blob", new byte[] {(byte) 0xaa, (byte) 0x55})
+ .add("lolwat", "kittens");
cursor.newRow();
cursor.newRow()
- .offer("string", "zero")
- .offer("string", "one")
- .offer("string", "two")
- .offer("lolwat", "kittens");
+ .add("string", "zero")
+ .add("string", "one")
+ .add("string", "two")
+ .add("lolwat", "kittens");
assertTrue(cursor.moveToFirst());
assertEquals("foobar", cursor.getString(0));
diff --git a/docs/html/training/id-auth/authenticate.jd b/docs/html/training/id-auth/authenticate.jd
index 3084bea..65dbc39 100644
--- a/docs/html/training/id-auth/authenticate.jd
+++ b/docs/html/training/id-auth/authenticate.jd
@@ -79,7 +79,7 @@ a valid auth token from the Android Account Manager"/>
<p>To get an auth token you first need to request the
{@link android.Manifest.permission#ACCOUNT_MANAGER}
-to yourmanifest file. To actually do anything useful with the
+to your manifest file. To actually do anything useful with the
token, you'll also need to add the {@link android.Manifest.permission#INTERNET}
permission.</p>
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 4193dbb..e3adc59 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -56,15 +56,26 @@ public class BitmapFactory {
* mutable even when decoding a resource which would normally result in
* an immutable bitmap.</p>
*
+ * <p>You should still always use the returned Bitmap of the decode
+ * method and not assume that reusing the bitmap worked, due to the
+ * constraints outlined above and failure situations that can occur.
+ * Checking whether the return value matches the value of the inBitmap
+ * set in the Options structure will indicate if the bitmap was reused,
+ * but in all cases you should use the Bitmap returned by the decoding
+ * function to ensure that you are using the bitmap that was used as the
+ * decode destination.</p>
+ *
+ * <h3>Usage with BitmapFactory</h3>
+ *
* <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, any
- * mutable bitmap can be reused to decode any other bitmaps as long as
- * the resulting {@link Bitmap#getByteCount() byte count} of the decoded
- * bitmap is less than or equal to the {@link
+ * mutable bitmap can be reused by {@link BitmapFactory} to decode any
+ * other bitmaps as long as the resulting {@link Bitmap#getByteCount()
+ * byte count} of the decoded bitmap is less than or equal to the {@link
* Bitmap#getAllocationByteCount() allocated byte count} of the reused
* bitmap. This can be because the intrinsic size is smaller, or its
* size post scaling (for density / sample size) is smaller.</p>
*
- * <p>Prior to {@link android.os.Build.VERSION_CODES#KITKAT}
+ * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT}
* additional constraints apply: The image being decoded (whether as a
* resource or as a stream) must be in jpeg or png format. Only equal
* sized bitmaps are supported, with {@link #inSampleSize} set to 1.
@@ -72,14 +83,17 @@ public class BitmapFactory {
* configuration} of the reused bitmap will override the setting of
* {@link #inPreferredConfig}, if set.</p>
*
- * <p>You should still always use the returned Bitmap of the decode
- * method and not assume that reusing the bitmap worked, due to the
- * constraints outlined above and failure situations that can occur.
- * Checking whether the return value matches the value of the inBitmap
- * set in the Options structure will indicate if the bitmap was reused,
- * but in all cases you should use the Bitmap returned by the decoding
- * function to ensure that you are using the bitmap that was used as the
- * decode destination.</p>
+ * <h3>Usage with BitmapRegionDecoder</h3>
+ *
+ * <p>BitmapRegionDecoder will draw its requested content into the Bitmap
+ * provided, clipping if the output content size (post scaling) is larger
+ * than the provided Bitmap. The provided Bitmap's width, height, and
+ * {@link Bitmap.Config} will not be changed.
+ *
+ * <p class="note">BitmapRegionDecoder support for {@link #inBitmap} was
+ * introduced in {@link android.os.Build.VERSION_CODES#JELLY_BEAN}. All
+ * formats supported by BitmapRegionDecoder support Bitmap reuse via
+ * {@link #inBitmap}.</p>
*
* @see Bitmap#reconfigure(int,int, android.graphics.Bitmap.Config)
*/
@@ -229,6 +243,9 @@ public class BitmapFactory {
* rather than relying on the graphics system scaling it each time it
* is drawn to a Canvas.
*
+ * <p>BitmapRegionDecoder ignores this flag, and will not scale output
+ * based on density. (though {@link #inSampleSize} is supported)</p>
+ *
* <p>This flag is turned on by default and should be turned off if you need
* a non-scaled version of the bitmap. Nine-patch bitmaps ignore this
* flag and are always scaled.
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index 0230583..d96d6d8 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -19,16 +19,16 @@ package android.graphics;
public class PixelFormat
{
/* these constants need to match those in hardware/hardware.h */
-
+
public static final int UNKNOWN = 0;
/** System chooses a format that supports translucency (many alpha bits) */
public static final int TRANSLUCENT = -3;
- /**
+ /**
* System chooses a format that supports transparency
- * (at least 1 alpha bit)
- */
+ * (at least 1 alpha bit)
+ */
public static final int TRANSPARENT = -2;
/** System chooses an opaque format (no alpha bits required) */
@@ -54,28 +54,28 @@ public class PixelFormat
/**
- * @deprecated use {@link android.graphics.ImageFormat#NV16
+ * @deprecated use {@link android.graphics.ImageFormat#NV16
* ImageFormat.NV16} instead.
*/
@Deprecated
public static final int YCbCr_422_SP= 0x10;
/**
- * @deprecated use {@link android.graphics.ImageFormat#NV21
+ * @deprecated use {@link android.graphics.ImageFormat#NV21
* ImageFormat.NV21} instead.
*/
@Deprecated
public static final int YCbCr_420_SP= 0x11;
/**
- * @deprecated use {@link android.graphics.ImageFormat#YUY2
+ * @deprecated use {@link android.graphics.ImageFormat#YUY2
* ImageFormat.YUY2} instead.
*/
@Deprecated
public static final int YCbCr_422_I = 0x14;
/**
- * @deprecated use {@link android.graphics.ImageFormat#JPEG
+ * @deprecated use {@link android.graphics.ImageFormat#JPEG
* ImageFormat.JPEG} instead.
*/
@Deprecated
@@ -95,6 +95,7 @@ public class PixelFormat
case RGB_565:
case RGBA_5551:
case RGBA_4444:
+ case LA_88:
info.bitsPerPixel = 16;
info.bytesPerPixel = 2;
break;
@@ -131,7 +132,7 @@ public class PixelFormat
}
return false;
}
-
+
public int bytesPerPixel;
public int bitsPerPixel;
}
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 690493d..cbc4e5a 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -184,7 +184,7 @@ static jint
nContextCreate(JNIEnv *_env, jobject _this, jint dev, jint ver, jint sdkVer, jint ct)
{
LOG_API("nContextCreate");
- return (jint)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, false, false);
+ return (jint)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, 0);
}
static jint
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 22b1485..e8456af 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -732,7 +732,7 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int
if (mRs == 0) {
mRs = new RSC::RS();
- if (!mRs->init(true, true)) {
+ if (!mRs->init(RSC::RS_INIT_LOW_LATENCY & RSC::RS_INIT_SYNCHRONOUS)) {
ALOGE("blur RS failed to init");
}
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
index 2cf1b2d..e83c5ba 100644
--- a/media/java/android/media/SubtitleController.java
+++ b/media/java/android/media/SubtitleController.java
@@ -20,8 +20,7 @@ import java.util.Locale;
import java.util.Vector;
import android.content.Context;
-import android.media.MediaPlayer.OnSubtitleDataListener;
-import android.view.View;
+import android.media.SubtitleTrack.RenderingWidget;
import android.view.accessibility.CaptioningManager;
/**
@@ -32,7 +31,6 @@ import android.view.accessibility.CaptioningManager;
* @hide
*/
public class SubtitleController {
- private Context mContext;
private MediaTimeProvider mTimeProvider;
private Vector<Renderer> mRenderers;
private Vector<SubtitleTrack> mTracks;
@@ -50,7 +48,6 @@ public class SubtitleController {
Context context,
MediaTimeProvider timeProvider,
Listener listener) {
- mContext = context;
mTimeProvider = timeProvider;
mListener = listener;
@@ -79,11 +76,11 @@ public class SubtitleController {
return mSelectedTrack;
}
- private View getSubtitleView() {
+ private RenderingWidget getRenderingWidget() {
if (mSelectedTrack == null) {
return null;
}
- return mSelectedTrack.getView();
+ return mSelectedTrack.getRenderingWidget();
}
/**
@@ -110,7 +107,7 @@ public class SubtitleController {
}
mSelectedTrack = track;
- mAnchor.setSubtitleView(getSubtitleView());
+ mAnchor.setSubtitleWidget(getRenderingWidget());
if (mSelectedTrack != null) {
mSelectedTrack.setTimeProvider(mTimeProvider);
@@ -268,17 +265,16 @@ public class SubtitleController {
}
/**
- * Subtitle anchor, an object that is able to display a subtitle view,
+ * Subtitle anchor, an object that is able to display a subtitle renderer,
* e.g. a VideoView.
*/
public interface Anchor {
/**
- * Anchor should set the subtitle view to the supplied view,
- * or none, if the supplied view is null.
- *
- * @param view subtitle view, or null
+ * Anchor should use the supplied subtitle rendering widget, or
+ * none if it is null.
+ * @hide
*/
- public void setSubtitleView(View view);
+ public void setSubtitleWidget(RenderingWidget subtitleWidget);
}
private Anchor mAnchor;
@@ -290,11 +286,11 @@ public class SubtitleController {
}
if (mAnchor != null) {
- mAnchor.setSubtitleView(null);
+ mAnchor.setSubtitleWidget(null);
}
mAnchor = anchor;
if (mAnchor != null) {
- mAnchor.setSubtitleView(getSubtitleView());
+ mAnchor.setSubtitleWidget(getRenderingWidget());
}
}
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index 09fb3f2..cb689af 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -16,11 +16,11 @@
package android.media;
+import android.graphics.Canvas;
import android.os.Handler;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.Pair;
-import android.view.View;
import java.util.Iterator;
import java.util.NoSuchElementException;
@@ -98,16 +98,16 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList
public abstract void onData(String data, boolean eos, long runID);
/**
- * Called when adding the subtitle rendering view to the view hierarchy, as
- * well as when showing or hiding the subtitle track, or when the video
+ * Called when adding the subtitle rendering widget to the view hierarchy,
+ * as well as when showing or hiding the subtitle track, or when the video
* surface position has changed.
*
- * @return the view object that displays this subtitle track. For most
- * renderers there should be a single shared view instance that is used
- * for all tracks supported by that renderer, as at most one subtitle
- * track is visible at one time.
+ * @return the widget that renders this subtitle track. For most renderers
+ * there should be a single shared instance that is used for all
+ * tracks supported by that renderer, as at most one subtitle track
+ * is visible at one time.
*/
- public abstract View getView();
+ public abstract RenderingWidget getRenderingWidget();
/**
* Called when the active cues have changed, and the contents of the subtitle
@@ -268,7 +268,7 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList
}
mVisible = true;
- getView().setVisibility(View.VISIBLE);
+ getRenderingWidget().setVisible(true);
if (mTimeProvider != null) {
mTimeProvider.scheduleUpdate(this);
}
@@ -283,7 +283,7 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList
if (mTimeProvider != null) {
mTimeProvider.cancelNotifications(this);
}
- getView().setVisibility(View.INVISIBLE);
+ getRenderingWidget().setVisible(false);
mVisible = false;
}
@@ -645,4 +645,61 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList
}
}
}
+
+ /**
+ * Interface for rendering subtitles onto a Canvas.
+ */
+ public interface RenderingWidget {
+ /**
+ * Sets the widget's callback, which is used to send updates when the
+ * rendered data has changed.
+ *
+ * @param callback update callback
+ */
+ public void setOnChangedListener(OnChangedListener callback);
+
+ /**
+ * Sets the widget's size.
+ *
+ * @param width width in pixels
+ * @param height height in pixels
+ */
+ public void setSize(int width, int height);
+
+ /**
+ * Sets whether the widget should draw subtitles.
+ *
+ * @param visible true if subtitles should be drawn, false otherwise
+ */
+ public void setVisible(boolean visible);
+
+ /**
+ * Renders subtitles onto a {@link Canvas}.
+ *
+ * @param c canvas on which to render subtitles
+ */
+ public void draw(Canvas c);
+
+ /**
+ * Called when the widget is attached to a window.
+ */
+ public void onAttachedToWindow();
+
+ /**
+ * Called when the widget is detached from a window.
+ */
+ public void onDetachedFromWindow();
+
+ /**
+ * Callback used to send updates about changes to rendering data.
+ */
+ public interface OnChangedListener {
+ /**
+ * Called when the rendering data has changed.
+ *
+ * @param renderingWidget the widget whose data has changed
+ */
+ public void onChanged(RenderingWidget renderingWidget);
+ }
+ }
}
diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java
index 527c57f..74773a8 100644
--- a/media/java/android/media/WebVttRenderer.java
+++ b/media/java/android/media/WebVttRenderer.java
@@ -1,12 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.media;
import android.content.Context;
+import android.text.SpannableStringBuilder;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.Gravity;
import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.TextView;
+import android.view.ViewGroup;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+import android.widget.LinearLayout;
+
+import com.android.internal.widget.SubtitleView;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -14,10 +39,12 @@ import java.util.Vector;
/** @hide */
public class WebVttRenderer extends SubtitleController.Renderer {
- private TextView mMyTextView;
+ private final Context mContext;
- public WebVttRenderer(Context context, AttributeSet attrs) {
- mMyTextView = new WebVttView(context, attrs);
+ private WebVttRenderingWidget mRenderingWidget;
+
+ public WebVttRenderer(Context context) {
+ mContext = context;
}
@Override
@@ -30,19 +57,11 @@ public class WebVttRenderer extends SubtitleController.Renderer {
@Override
public SubtitleTrack createTrack(MediaFormat format) {
- return new WebVttTrack(format, mMyTextView);
- }
-}
+ if (mRenderingWidget == null) {
+ mRenderingWidget = new WebVttRenderingWidget(mContext);
+ }
-/** @hide */
-class WebVttView extends TextView {
- public WebVttView(Context context, AttributeSet attrs) {
- super(context, attrs);
- setTextColor(0xffffff00);
- setTextSize(46);
- setTextAlignment(TextView.TEXT_ALIGNMENT_CENTER);
- setLayoutParams(new LayoutParams(
- LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
+ return new WebVttTrack(mRenderingWidget, format);
}
}
@@ -954,26 +973,26 @@ interface WebVttCueListener {
class WebVttTrack extends SubtitleTrack implements WebVttCueListener {
private static final String TAG = "WebVttTrack";
- private final TextView mTextView;
-
private final WebVttParser mParser = new WebVttParser(this);
private final UnstyledTextExtractor mExtractor =
new UnstyledTextExtractor();
private final Tokenizer mTokenizer = new Tokenizer(mExtractor);
private final Vector<Long> mTimestamps = new Vector<Long>();
+ private final WebVttRenderingWidget mRenderingWidget;
private final Map<String, TextTrackRegion> mRegions =
new HashMap<String, TextTrackRegion>();
private Long mCurrentRunID;
- WebVttTrack(MediaFormat format, TextView textView) {
+ WebVttTrack(WebVttRenderingWidget renderingWidget, MediaFormat format) {
super(format);
- mTextView = textView;
+
+ mRenderingWidget = renderingWidget;
}
@Override
- public View getView() {
- return mTextView;
+ public WebVttRenderingWidget getRenderingWidget() {
+ return mRenderingWidget;
}
@Override
@@ -1051,6 +1070,7 @@ class WebVttTrack extends SubtitleTrack implements WebVttCueListener {
}
}
+ @Override
public void updateView(Vector<SubtitleTrack.Cue> activeCues) {
if (!mVisible) {
// don't keep the state if we are not visible
@@ -1066,29 +1086,737 @@ class WebVttTrack extends SubtitleTrack implements WebVttCueListener {
Log.d(TAG, "at (illegal state) the active cues are:");
}
}
- StringBuilder text = new StringBuilder();
- StringBuilder lineBuilder = new StringBuilder();
- for (Cue o: activeCues) {
- TextTrackCue cue = (TextTrackCue)o;
- if (DEBUG) Log.d(TAG, cue.toString());
- for (TextTrackCueSpan[] line: cue.mLines) {
- for (TextTrackCueSpan span: line) {
- if (!span.mEnabled) {
- continue;
- }
- lineBuilder.append(span.mText);
+
+ mRenderingWidget.setActiveCues(activeCues);
+ }
+}
+
+/**
+ * Widget capable of rendering WebVTT captions.
+ *
+ * @hide
+ */
+class WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.RenderingWidget {
+ private static final boolean DEBUG = false;
+ private static final int DEBUG_REGION_BACKGROUND = 0x800000FF;
+ private static final int DEBUG_CUE_BACKGROUND = 0x80FF0000;
+
+ /** WebVtt specifies line height as 5.3% of the viewport height. */
+ private static final float LINE_HEIGHT_RATIO = 0.0533f;
+
+ /** Map of active regions, used to determine enter/exit. */
+ private final ArrayMap<TextTrackRegion, RegionLayout> mRegionBoxes =
+ new ArrayMap<TextTrackRegion, RegionLayout>();
+
+ /** Map of active cues, used to determine enter/exit. */
+ private final ArrayMap<TextTrackCue, CueLayout> mCueBoxes =
+ new ArrayMap<TextTrackCue, CueLayout>();
+
+ /** Captioning manager, used to obtain and track caption properties. */
+ private final CaptioningManager mManager;
+
+ /** Callback for rendering changes. */
+ private OnChangedListener mListener;
+
+ /** Current caption style. */
+ private CaptionStyle mCaptionStyle;
+
+ /** Current font size, computed from font scaling factor and height. */
+ private float mFontSize;
+
+ /** Whether a caption style change listener is registered. */
+ private boolean mHasChangeListener;
+
+ public WebVttRenderingWidget(Context context) {
+ this(context, null);
+ }
+
+ public WebVttRenderingWidget(Context context, AttributeSet attrs) {
+ this(context, null, 0);
+ }
+
+ public WebVttRenderingWidget(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // Cannot render text over video when layer type is hardware.
+ setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+ mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+ mCaptionStyle = mManager.getUserStyle();
+ mFontSize = mManager.getFontScale() * getHeight() * LINE_HEIGHT_RATIO;
+ }
+
+ @Override
+ public void setSize(int width, int height) {
+ final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+ measure(widthSpec, heightSpec);
+ layout(0, 0, width, height);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ manageChangeListener();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ manageChangeListener();
+ }
+
+ @Override
+ public void setOnChangedListener(OnChangedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ setVisibility(View.VISIBLE);
+ } else {
+ setVisibility(View.GONE);
+ }
+
+ manageChangeListener();
+ }
+
+ /**
+ * Manages whether this renderer is listening for caption style changes.
+ */
+ private void manageChangeListener() {
+ final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE;
+ if (mHasChangeListener != needsListener) {
+ mHasChangeListener = needsListener;
+
+ if (needsListener) {
+ mManager.addCaptioningChangeListener(mCaptioningListener);
+
+ final CaptionStyle captionStyle = mManager.getUserStyle();
+ final float fontSize = mManager.getFontScale() * getHeight() * LINE_HEIGHT_RATIO;
+ setCaptionStyle(captionStyle, fontSize);
+ } else {
+ mManager.removeCaptioningChangeListener(mCaptioningListener);
+ }
+ }
+ }
+
+ public void setActiveCues(Vector<SubtitleTrack.Cue> activeCues) {
+ final Context context = getContext();
+ final CaptionStyle captionStyle = mCaptionStyle;
+ final float fontSize = mFontSize;
+
+ prepForPrune();
+
+ // Ensure we have all necessary cue and region boxes.
+ final int count = activeCues.size();
+ for (int i = 0; i < count; i++) {
+ final TextTrackCue cue = (TextTrackCue) activeCues.get(i);
+ final TextTrackRegion region = cue.mRegion;
+ if (region != null) {
+ RegionLayout regionBox = mRegionBoxes.get(region);
+ if (regionBox == null) {
+ regionBox = new RegionLayout(context, region, captionStyle, fontSize);
+ mRegionBoxes.put(region, regionBox);
+ addView(regionBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
- if (lineBuilder.length() > 0) {
- text.append(lineBuilder.toString()).append("\n");
- lineBuilder.delete(0, lineBuilder.length());
+ regionBox.put(cue);
+ } else {
+ CueLayout cueBox = mCueBoxes.get(cue);
+ if (cueBox == null) {
+ cueBox = new CueLayout(context, cue, captionStyle, fontSize);
+ mCueBoxes.put(cue, cueBox);
+ addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
+ cueBox.update();
+ cueBox.setOrder(i);
+ }
+ }
+
+ prune();
+
+ // Force measurement and layout.
+ final int width = getWidth();
+ final int height = getHeight();
+ setSize(width, height);
+
+ if (mListener != null) {
+ mListener.onChanged(this);
+ }
+ }
+
+ private void setCaptionStyle(CaptionStyle captionStyle, float fontSize) {
+ mCaptionStyle = captionStyle;
+ mFontSize = fontSize;
+
+ final int cueCount = mCueBoxes.size();
+ for (int i = 0; i < cueCount; i++) {
+ final CueLayout cueBox = mCueBoxes.valueAt(i);
+ cueBox.setCaptionStyle(captionStyle, fontSize);
+ }
+
+ final int regionCount = mRegionBoxes.size();
+ for (int i = 0; i < regionCount; i++) {
+ final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+ regionBox.setCaptionStyle(captionStyle, fontSize);
+ }
+ }
+
+ /**
+ * Remove inactive cues and regions.
+ */
+ private void prune() {
+ int regionCount = mRegionBoxes.size();
+ for (int i = 0; i < regionCount; i++) {
+ final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+ if (regionBox.prune()) {
+ removeView(regionBox);
+ mRegionBoxes.removeAt(i);
+ regionCount--;
+ i--;
}
}
- if (mTextView != null) {
- if (DEBUG) Log.d(TAG, "updating to " + text.toString());
- mTextView.setText(text.toString());
- mTextView.postInvalidate();
+ int cueCount = mCueBoxes.size();
+ for (int i = 0; i < cueCount; i++) {
+ final CueLayout cueBox = mCueBoxes.valueAt(i);
+ if (!cueBox.isActive()) {
+ removeView(cueBox);
+ mCueBoxes.removeAt(i);
+ cueCount--;
+ i--;
+ }
+ }
+ }
+
+ /**
+ * Reset active cues and regions.
+ */
+ private void prepForPrune() {
+ final int regionCount = mRegionBoxes.size();
+ for (int i = 0; i < regionCount; i++) {
+ final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+ regionBox.prepForPrune();
+ }
+
+ final int cueCount = mCueBoxes.size();
+ for (int i = 0; i < cueCount; i++) {
+ final CueLayout cueBox = mCueBoxes.valueAt(i);
+ cueBox.prepForPrune();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ final int regionCount = mRegionBoxes.size();
+ for (int i = 0; i < regionCount; i++) {
+ final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+ regionBox.measureForParent(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ final int cueCount = mCueBoxes.size();
+ for (int i = 0; i < cueCount; i++) {
+ final CueLayout cueBox = mCueBoxes.valueAt(i);
+ cueBox.measureForParent(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int viewportWidth = r - l;
+ final int viewportHeight = b - t;
+
+ setCaptionStyle(mCaptionStyle,
+ mManager.getFontScale() * LINE_HEIGHT_RATIO * viewportHeight);
+
+ final int regionCount = mRegionBoxes.size();
+ for (int i = 0; i < regionCount; i++) {
+ final RegionLayout regionBox = mRegionBoxes.valueAt(i);
+ layoutRegion(viewportWidth, viewportHeight, regionBox);
+ }
+
+ final int cueCount = mCueBoxes.size();
+ for (int i = 0; i < cueCount; i++) {
+ final CueLayout cueBox = mCueBoxes.valueAt(i);
+ layoutCue(viewportWidth, viewportHeight, cueBox);
+ }
+ }
+
+ /**
+ * Lays out a region within the viewport. The region handles layout for
+ * contained cues.
+ */
+ private void layoutRegion(
+ int viewportWidth, int viewportHeight,
+ RegionLayout regionBox) {
+ final TextTrackRegion region = regionBox.getRegion();
+ final int regionHeight = regionBox.getMeasuredHeight();
+ final int regionWidth = regionBox.getMeasuredWidth();
+
+ // TODO: Account for region anchor point.
+ final float x = region.mViewportAnchorPointX;
+ final float y = region.mViewportAnchorPointY;
+ final int left = (int) (x * (viewportWidth - regionWidth) / 100);
+ final int top = (int) (y * (viewportHeight - regionHeight) / 100);
+
+ regionBox.layout(left, top, left + regionWidth, top + regionHeight);
+ }
+
+ /**
+ * Lays out a cue within the viewport.
+ */
+ private void layoutCue(
+ int viewportWidth, int viewportHeight, CueLayout cueBox) {
+ final TextTrackCue cue = cueBox.getCue();
+ final int direction = getLayoutDirection();
+ final int absAlignment = resolveCueAlignment(direction, cue.mAlignment);
+ final boolean cueSnapToLines = cue.mSnapToLines;
+
+ int size = 100 * cueBox.getMeasuredWidth() / viewportWidth;
+
+ // Determine raw x-position.
+ int xPosition;
+ switch (absAlignment) {
+ case TextTrackCue.ALIGNMENT_LEFT:
+ xPosition = cue.mTextPosition;
+ break;
+ case TextTrackCue.ALIGNMENT_RIGHT:
+ xPosition = cue.mTextPosition - size;
+ break;
+ case TextTrackCue.ALIGNMENT_MIDDLE:
+ default:
+ xPosition = cue.mTextPosition - size / 2;
+ break;
+ }
+
+ // Adjust x-position for layout.
+ if (direction == LAYOUT_DIRECTION_RTL) {
+ xPosition = 100 - xPosition;
+ }
+
+ // If the text track cue snap-to-lines flag is set, adjust
+ // x-position and size for padding. This is equivalent to placing the
+ // cue within the title-safe area.
+ if (cueSnapToLines) {
+ final int paddingLeft = 100 * getPaddingLeft() / viewportWidth;
+ final int paddingRight = 100 * getPaddingRight() / viewportWidth;
+ if (xPosition < paddingLeft && xPosition + size > paddingLeft) {
+ xPosition += paddingLeft;
+ size -= paddingLeft;
+ }
+ final float rightEdge = 100 - paddingRight;
+ if (xPosition < rightEdge && xPosition + size > rightEdge) {
+ size -= paddingRight;
+ }
+ }
+
+ // Compute absolute left position and width.
+ final int left = xPosition * viewportWidth / 100;
+ final int width = size * viewportWidth / 100;
+
+ // Determine initial y-position.
+ final int yPosition = calculateLinePosition(cueBox);
+
+ // Compute absolute final top position and height.
+ final int height = cueBox.getMeasuredHeight();
+ final int top;
+ if (yPosition < 0) {
+ // TODO: This needs to use the actual height of prior boxes.
+ top = viewportHeight + yPosition * height;
+ } else {
+ top = yPosition * (viewportHeight - height) / 100;
+ }
+
+ // Layout cue in final position.
+ cueBox.layout(left, top, left + width, top + height);
+ }
+
+ /**
+ * Calculates the line position for a cue.
+ * <p>
+ * If the resulting position is negative, it represents a bottom-aligned
+ * position relative to the number of active cues. Otherwise, it represents
+ * a percentage [0-100] of the viewport height.
+ */
+ private int calculateLinePosition(CueLayout cueBox) {
+ final TextTrackCue cue = cueBox.getCue();
+ final Integer linePosition = cue.mLinePosition;
+ final boolean snapToLines = cue.mSnapToLines;
+ final boolean autoPosition = (linePosition == null);
+
+ if (!snapToLines && !autoPosition && (linePosition < 0 || linePosition > 100)) {
+ // Invalid line position defaults to 100.
+ return 100;
+ } else if (!autoPosition) {
+ // Use the valid, supplied line position.
+ return linePosition;
+ } else if (!snapToLines) {
+ // Automatic, non-snapped line position defaults to 100.
+ return 100;
+ } else {
+ // Automatic snapped line position uses active cue order.
+ return -(cueBox.mOrder + 1);
+ }
+ }
+
+ /**
+ * Resolves cue alignment according to the specified layout direction.
+ */
+ private static int resolveCueAlignment(int layoutDirection, int alignment) {
+ switch (alignment) {
+ case TextTrackCue.ALIGNMENT_START:
+ return layoutDirection == View.LAYOUT_DIRECTION_LTR ?
+ TextTrackCue.ALIGNMENT_LEFT : TextTrackCue.ALIGNMENT_RIGHT;
+ case TextTrackCue.ALIGNMENT_END:
+ return layoutDirection == View.LAYOUT_DIRECTION_LTR ?
+ TextTrackCue.ALIGNMENT_RIGHT : TextTrackCue.ALIGNMENT_LEFT;
+ }
+ return alignment;
+ }
+
+ private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() {
+ @Override
+ public void onFontScaleChanged(float fontScale) {
+ final float fontSize = fontScale * getHeight() * LINE_HEIGHT_RATIO;
+ setCaptionStyle(mCaptionStyle, fontSize);
+ }
+
+ @Override
+ public void onUserStyleChanged(CaptionStyle userStyle) {
+ setCaptionStyle(userStyle, mFontSize);
+ }
+ };
+
+ /**
+ * A text track region represents a portion of the video viewport and
+ * provides a rendering area for text track cues.
+ */
+ private static class RegionLayout extends LinearLayout {
+ private final ArrayList<CueLayout> mRegionCueBoxes = new ArrayList<CueLayout>();
+ private final TextTrackRegion mRegion;
+
+ private CaptionStyle mCaptionStyle;
+ private float mFontSize;
+
+ public RegionLayout(Context context, TextTrackRegion region, CaptionStyle captionStyle,
+ float fontSize) {
+ super(context);
+
+ mRegion = region;
+ mCaptionStyle = captionStyle;
+ mFontSize = fontSize;
+
+ // TODO: Add support for vertical text
+ setOrientation(VERTICAL);
+
+ if (DEBUG) {
+ setBackgroundColor(DEBUG_REGION_BACKGROUND);
+ }
+ }
+
+ public void setCaptionStyle(CaptionStyle captionStyle, float fontSize) {
+ mCaptionStyle = captionStyle;
+ mFontSize = fontSize;
+
+ final int cueCount = mRegionCueBoxes.size();
+ for (int i = 0; i < cueCount; i++) {
+ final CueLayout cueBox = mRegionCueBoxes.get(i);
+ cueBox.setCaptionStyle(captionStyle, fontSize);
+ }
+ }
+
+ /**
+ * Performs the parent's measurement responsibilities, then
+ * automatically performs its own measurement.
+ */
+ public void measureForParent(int widthMeasureSpec, int heightMeasureSpec) {
+ final TextTrackRegion region = mRegion;
+ final int specWidth = MeasureSpec.getSize(widthMeasureSpec);
+ final int specHeight = MeasureSpec.getSize(heightMeasureSpec);
+ final int width = (int) region.mWidth;
+
+ // Determine the absolute maximum region size as the requested size.
+ final int size = width * specWidth / 100;
+
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.AT_MOST);
+ measure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ /**
+ * Prepares this region for pruning by setting all tracks as inactive.
+ * <p>
+ * Tracks that are added or updated using {@link #put(TextTrackCue)}
+ * after this calling this method will be marked as active.
+ */
+ public void prepForPrune() {
+ final int cueCount = mRegionCueBoxes.size();
+ for (int i = 0; i < cueCount; i++) {
+ final CueLayout cueBox = mRegionCueBoxes.get(i);
+ cueBox.prepForPrune();
+ }
+ }
+
+ /**
+ * Adds a {@link TextTrackCue} to this region. If the track had already
+ * been added, updates its active state.
+ *
+ * @param cue
+ */
+ public void put(TextTrackCue cue) {
+ final int cueCount = mRegionCueBoxes.size();
+ for (int i = 0; i < cueCount; i++) {
+ final CueLayout cueBox = mRegionCueBoxes.get(i);
+ if (cueBox.getCue() == cue) {
+ cueBox.update();
+ return;
+ }
+ }
+
+ final CueLayout cueBox = new CueLayout(getContext(), cue, mCaptionStyle, mFontSize);
+ addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+
+ if (getChildCount() > mRegion.mLines) {
+ removeViewAt(0);
+ }
+ }
+
+ /**
+ * Remove all inactive tracks from this region.
+ *
+ * @return true if this region is empty and should be pruned
+ */
+ public boolean prune() {
+ int cueCount = mRegionCueBoxes.size();
+ for (int i = 0; i < cueCount; i++) {
+ final CueLayout cueBox = mRegionCueBoxes.get(i);
+ if (!cueBox.isActive()) {
+ mRegionCueBoxes.remove(i);
+ removeView(cueBox);
+ cueCount--;
+ i--;
+ }
+ }
+
+ return mRegionCueBoxes.isEmpty();
+ }
+
+ /**
+ * @return the region data backing this layout
+ */
+ public TextTrackRegion getRegion() {
+ return mRegion;
+ }
+ }
+
+ /**
+ * A text track cue is the unit of time-sensitive data in a text track,
+ * corresponding for instance for subtitles and captions to the text that
+ * appears at a particular time and disappears at another time.
+ * <p>
+ * A single cue may contain multiple {@link SpanLayout}s, each representing a
+ * single line of text.
+ */
+ private static class CueLayout extends LinearLayout {
+ public final TextTrackCue mCue;
+
+ private CaptionStyle mCaptionStyle;
+ private float mFontSize;
+
+ private boolean mActive;
+ private int mOrder;
+
+ public CueLayout(
+ Context context, TextTrackCue cue, CaptionStyle captionStyle, float fontSize) {
+ super(context);
+
+ mCue = cue;
+ mCaptionStyle = captionStyle;
+ mFontSize = fontSize;
+
+ // TODO: Add support for vertical text.
+ final boolean horizontal = cue.mWritingDirection
+ == TextTrackCue.WRITING_DIRECTION_HORIZONTAL;
+ setOrientation(horizontal ? VERTICAL : HORIZONTAL);
+
+ switch (cue.mAlignment) {
+ case TextTrackCue.ALIGNMENT_END:
+ setGravity(Gravity.END);
+ break;
+ case TextTrackCue.ALIGNMENT_LEFT:
+ setGravity(Gravity.LEFT);
+ break;
+ case TextTrackCue.ALIGNMENT_MIDDLE:
+ setGravity(horizontal
+ ? Gravity.CENTER_HORIZONTAL : Gravity.CENTER_VERTICAL);
+ break;
+ case TextTrackCue.ALIGNMENT_RIGHT:
+ setGravity(Gravity.RIGHT);
+ break;
+ case TextTrackCue.ALIGNMENT_START:
+ setGravity(Gravity.START);
+ break;
+ }
+
+ if (DEBUG) {
+ setBackgroundColor(DEBUG_CUE_BACKGROUND);
+ }
+
+ update();
+ }
+
+ public void setCaptionStyle(CaptionStyle style, float fontSize) {
+ mCaptionStyle = style;
+ mFontSize = fontSize;
+
+ final int n = getChildCount();
+ for (int i = 0; i < n; i++) {
+ final View child = getChildAt(i);
+ if (child instanceof SpanLayout) {
+ ((SpanLayout) child).setCaptionStyle(style, fontSize);
+ }
+ }
+ }
+
+ public void prepForPrune() {
+ mActive = false;
+ }
+
+ public void update() {
+ mActive = true;
+
+ removeAllViews();
+
+ final CaptionStyle captionStyle = mCaptionStyle;
+ final float fontSize = mFontSize;
+ final TextTrackCueSpan[][] lines = mCue.mLines;
+ final int lineCount = lines.length;
+ for (int i = 0; i < lineCount; i++) {
+ final SpanLayout lineBox = new SpanLayout(getContext(), lines[i]);
+ lineBox.setCaptionStyle(captionStyle, fontSize);
+
+ addView(lineBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ /**
+ * Performs the parent's measurement responsibilities, then
+ * automatically performs its own measurement.
+ */
+ public void measureForParent(int widthMeasureSpec, int heightMeasureSpec) {
+ final TextTrackCue cue = mCue;
+ final int specWidth = MeasureSpec.getSize(widthMeasureSpec);
+ final int specHeight = MeasureSpec.getSize(heightMeasureSpec);
+ final int direction = getLayoutDirection();
+ final int absAlignment = resolveCueAlignment(direction, cue.mAlignment);
+
+ // Determine the maximum size of cue based on its starting position
+ // and the direction in which it grows.
+ final int maximumSize;
+ switch (absAlignment) {
+ case TextTrackCue.ALIGNMENT_LEFT:
+ maximumSize = 100 - cue.mTextPosition;
+ break;
+ case TextTrackCue.ALIGNMENT_RIGHT:
+ maximumSize = cue.mTextPosition;
+ break;
+ case TextTrackCue.ALIGNMENT_MIDDLE:
+ if (cue.mTextPosition <= 50) {
+ maximumSize = cue.mTextPosition * 2;
+ } else {
+ maximumSize = (100 - cue.mTextPosition) * 2;
+ }
+ break;
+ default:
+ maximumSize = 0;
+ }
+
+ // Determine absolute maximum cue size as the smaller of the
+ // requested size and the maximum theoretical size.
+ final int size = Math.min(cue.mSize, maximumSize) * specWidth / 100;
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.AT_MOST);
+ measure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ /**
+ * Sets the order of this cue in the list of active cues.
+ *
+ * @param order the order of this cue in the list of active cues
+ */
+ public void setOrder(int order) {
+ mOrder = order;
+ }
+
+ /**
+ * @return whether this cue is marked as active
+ */
+ public boolean isActive() {
+ return mActive;
+ }
+
+ /**
+ * @return the cue data backing this layout
+ */
+ public TextTrackCue getCue() {
+ return mCue;
+ }
+ }
+
+ /**
+ * A text track line represents a single line of text within a cue.
+ * <p>
+ * A single line may contain multiple spans, each representing a section of
+ * text that may be enabled or disabled at a particular time.
+ */
+ private static class SpanLayout extends SubtitleView {
+ private final SpannableStringBuilder mBuilder = new SpannableStringBuilder();
+ private final TextTrackCueSpan[] mSpans;
+
+ public SpanLayout(Context context, TextTrackCueSpan[] spans) {
+ super(context);
+
+ mSpans = spans;
+
+ update();
+ }
+
+ public void update() {
+ final SpannableStringBuilder builder = mBuilder;
+ final TextTrackCueSpan[] spans = mSpans;
+
+ builder.clear();
+ builder.clearSpans();
+
+ final int spanCount = spans.length;
+ for (int i = 0; i < spanCount; i++) {
+ final TextTrackCueSpan span = spans[i];
+ if (span.mEnabled) {
+ builder.append(spans[i].mText);
+ }
+ }
+
+ setText(builder);
+ }
+
+ public void setCaptionStyle(CaptionStyle captionStyle, float fontSize) {
+ setBackgroundColor(captionStyle.backgroundColor);
+ setForegroundColor(captionStyle.foregroundColor);
+ setEdgeColor(captionStyle.edgeColor);
+ setEdgeType(captionStyle.edgeType);
+ setTypeface(captionStyle.getTypeface());
+ setTextSize(fontSize);
}
}
}
diff --git a/packages/DocumentsUI/res/drawable/item_background.xml b/packages/DocumentsUI/res/drawable/item_background.xml
index 4fb32fc..7447aa8 100644
--- a/packages/DocumentsUI/res/drawable/item_background.xml
+++ b/packages/DocumentsUI/res/drawable/item_background.xml
@@ -15,12 +15,20 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_activated="true" android:state_pressed="true" android:drawable="@*android:drawable/list_activated_holo" />
- <item android:state_activated="true" android:drawable="@*android:drawable/list_activated_holo" />
- <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@*android:drawable/list_selector_disabled_holo_light" />
- <item android:state_focused="true" android:state_enabled="false" android:drawable="@*android:drawable/list_selector_disabled_holo_light" />
- <item android:state_focused="true" android:state_pressed="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" />
- <item android:state_focused="false" android:state_pressed="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" />
- <item android:state_focused="true" android:drawable="@*android:drawable/list_focused_holo" />
- <item android:drawable="@android:color/transparent" />
+
+ <item android:state_enabled="false" android:state_selected="true" android:drawable="@*android:drawable/list_selector_disabled_holo_light" />
+ <item android:state_enabled="false" android:state_focused="true" android:drawable="@*android:drawable/list_selector_disabled_holo_light" />
+ <item android:state_enabled="false" android:state_pressed="true" android:drawable="@*android:drawable/list_selector_disabled_holo_light" />
+
+ <item android:state_activated="true" android:state_pressed="true" android:drawable="@*android:drawable/list_activated_holo" />
+ <item android:state_activated="true" android:drawable="@*android:drawable/list_activated_holo" />
+
+ <item android:state_focused="true" android:drawable="@*android:drawable/list_focused_holo" />
+ <item android:state_selected="true" android:drawable="@*android:drawable/list_focused_holo" />
+
+ <item android:state_pressed="true" android:state_focused="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" />
+ <item android:state_pressed="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" />
+
+ <item android:drawable="@android:color/transparent" />
+
</selector>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index e0b8d19..d8e60aa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -70,7 +70,7 @@ public class CreateDirectoryFragment extends DialogFragment {
try {
final Uri childUri = DocumentsContract.createDocument(
- resolver, cwd.uri, Document.MIME_TYPE_DIR, displayName);
+ resolver, cwd.derivedUri, Document.MIME_TYPE_DIR, displayName);
// Navigate into newly created child
final DocumentInfo childDoc = DocumentInfo.fromUri(resolver, childUri);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index e594437..45f028d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -20,6 +20,8 @@ import static com.android.documentsui.DocumentsActivity.TAG;
import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
+import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -29,6 +31,7 @@ import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
@@ -63,6 +66,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
import com.android.internal.util.Predicate;
@@ -91,43 +95,47 @@ public class DirectoryFragment extends Fragment {
private int mType = TYPE_NORMAL;
+ private int mLastMode = MODE_UNKNOWN;
+ private int mLastSortOrder = SORT_ORDER_UNKNOWN;
+
private Point mThumbSize;
private DocumentsAdapter mAdapter;
private LoaderCallbacks<DirectoryResult> mCallbacks;
private static final String EXTRA_TYPE = "type";
- private static final String EXTRA_AUTHORITY = "authority";
- private static final String EXTRA_ROOT_ID = "rootId";
- private static final String EXTRA_DOC_ID = "docId";
+ private static final String EXTRA_ROOT = "root";
+ private static final String EXTRA_DOC = "doc";
private static final String EXTRA_QUERY = "query";
- private static AtomicInteger sLoaderId = new AtomicInteger(4000);
+ /**
+ * MIME types that should always show thumbnails in list mode.
+ */
+ private static final String[] LIST_THUMBNAIL_MIMES = new String[] { "image/*", "video/*" };
- private int mLastSortOrder = -1;
+ private static AtomicInteger sLoaderId = new AtomicInteger(4000);
private final int mLoaderId = sLoaderId.incrementAndGet();
- public static void showNormal(FragmentManager fm, Uri uri) {
- show(fm, TYPE_NORMAL, uri.getAuthority(), null, DocumentsContract.getDocumentId(uri), null);
+ public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc) {
+ show(fm, TYPE_NORMAL, root, doc, null);
}
- public static void showSearch(FragmentManager fm, Uri uri, String query) {
- show(fm, TYPE_SEARCH, uri.getAuthority(), null, DocumentsContract.getDocumentId(uri),
- query);
+ public static void showSearch(
+ FragmentManager fm, RootInfo root, DocumentInfo doc, String query) {
+ show(fm, TYPE_SEARCH, root, doc, query);
}
public static void showRecentsOpen(FragmentManager fm) {
- show(fm, TYPE_RECENT_OPEN, null, null, null, null);
+ show(fm, TYPE_RECENT_OPEN, null, null, null);
}
- private static void show(FragmentManager fm, int type, String authority, String rootId,
- String docId, String query) {
+ private static void show(
+ FragmentManager fm, int type, RootInfo root, DocumentInfo doc, String query) {
final Bundle args = new Bundle();
args.putInt(EXTRA_TYPE, type);
- args.putString(EXTRA_AUTHORITY, authority);
- args.putString(EXTRA_ROOT_ID, rootId);
- args.putString(EXTRA_DOC_ID, docId);
+ args.putParcelable(EXTRA_ROOT, root);
+ args.putParcelable(EXTRA_DOC, doc);
args.putString(EXTRA_QUERY, query);
final DirectoryFragment fragment = new DirectoryFragment();
@@ -167,6 +175,7 @@ public class DirectoryFragment extends Fragment {
super.onActivityCreated(savedInstanceState);
final Context context = getActivity();
+ final State state = getDisplayState(DirectoryFragment.this);
mAdapter = new DocumentsAdapter();
mType = getArguments().getInt(EXTRA_TYPE);
@@ -174,35 +183,50 @@ public class DirectoryFragment extends Fragment {
mCallbacks = new LoaderCallbacks<DirectoryResult>() {
@Override
public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
- final State state = getDisplayState(DirectoryFragment.this);
-
- final String authority = getArguments().getString(EXTRA_AUTHORITY);
- final String rootId = getArguments().getString(EXTRA_ROOT_ID);
- final String docId = getArguments().getString(EXTRA_DOC_ID);
+ final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
+ final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
final String query = getArguments().getString(EXTRA_QUERY);
Uri contentsUri;
switch (mType) {
case TYPE_NORMAL:
- contentsUri = DocumentsContract.buildChildDocumentsUri(authority, docId);
- return new DirectoryLoader(context, rootId, contentsUri, state.sortOrder);
+ contentsUri = DocumentsContract.buildChildDocumentsUri(
+ doc.authority, doc.documentId);
+ return new DirectoryLoader(
+ context, root, doc, contentsUri, state.userSortOrder);
case TYPE_SEARCH:
contentsUri = DocumentsContract.buildSearchDocumentsUri(
- authority, docId, query);
- return new DirectoryLoader(context, rootId, contentsUri, state.sortOrder);
+ doc.authority, doc.documentId, query);
+ return new DirectoryLoader(
+ context, root, doc, contentsUri, state.userSortOrder);
case TYPE_RECENT_OPEN:
final RootsCache roots = DocumentsApplication.getRootsCache(context);
final List<RootInfo> matchingRoots = roots.getMatchingRoots(state);
- return new RecentLoader(context, matchingRoots);
+ return new RecentLoader(context, matchingRoots, state.acceptMimes);
default:
throw new IllegalStateException("Unknown type " + mType);
-
}
}
@Override
public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
+ if (!isAdded()) return;
+
mAdapter.swapCursor(result.cursor);
+
+ // Push latest state up to UI
+ // TODO: if mode change was racing with us, don't overwrite it
+ state.derivedMode = result.mode;
+ state.derivedSortOrder = result.sortOrder;
+ ((DocumentsActivity) context).onStateChanged();
+
+ updateDisplayState();
+
+ if (mLastSortOrder != state.derivedSortOrder) {
+ mLastSortOrder = state.derivedSortOrder;
+ mListView.smoothScrollToPosition(0);
+ mGridView.smoothScrollToPosition(0);
+ }
}
@Override
@@ -211,6 +235,9 @@ public class DirectoryFragment extends Fragment {
}
};
+ // Kick off loader at least once
+ getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
+
updateDisplayState();
}
@@ -220,22 +247,51 @@ public class DirectoryFragment extends Fragment {
updateDisplayState();
}
- public void updateDisplayState() {
+ public void onUserSortOrderChanged() {
+ // Sort order change always triggers reload; we'll trigger state change
+ // on the flip side.
+ getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
+ }
+
+ public void onUserModeChanged() {
+ final ContentResolver resolver = getActivity().getContentResolver();
final State state = getDisplayState(this);
- if (mLastSortOrder != state.sortOrder) {
- getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
- mLastSortOrder = state.sortOrder;
- }
+ final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
+ final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
- mListView.smoothScrollToPosition(0);
- mGridView.smoothScrollToPosition(0);
+ final Uri stateUri = RecentsProvider.buildState(
+ root.authority, root.rootId, doc.documentId);
+ final ContentValues values = new ContentValues();
+ values.put(StateColumns.MODE, state.userMode);
- mListView.setVisibility(state.mode == MODE_LIST ? View.VISIBLE : View.GONE);
- mGridView.setVisibility(state.mode == MODE_GRID ? View.VISIBLE : View.GONE);
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ resolver.insert(stateUri, values);
+ return null;
+ }
+ }.execute();
+
+ // Mode change is just visual change; no need to kick loader, and
+ // deliver change event immediately.
+ state.derivedMode = state.userMode;
+ ((DocumentsActivity) getActivity()).onStateChanged();
+
+ updateDisplayState();
+ }
+
+ private void updateDisplayState() {
+ final State state = getDisplayState(this);
mFilter = new MimePredicate(state.acceptMimes);
+ if (mLastMode == state.derivedMode) return;
+ mLastMode = state.derivedMode;
+
+ mListView.setVisibility(state.derivedMode == MODE_LIST ? View.VISIBLE : View.GONE);
+ mGridView.setVisibility(state.derivedMode == MODE_GRID ? View.VISIBLE : View.GONE);
+
final int choiceMode;
if (state.allowMultiple) {
choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL;
@@ -244,7 +300,7 @@ public class DirectoryFragment extends Fragment {
}
final int thumbSize;
- if (state.mode == MODE_GRID) {
+ if (state.derivedMode == MODE_GRID) {
thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
mListView.setAdapter(null);
mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
@@ -253,15 +309,15 @@ public class DirectoryFragment extends Fragment {
mGridView.setNumColumns(GridView.AUTO_FIT);
mGridView.setChoiceMode(choiceMode);
mCurrentView = mGridView;
- } else if (state.mode == MODE_LIST) {
- thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
+ } else if (state.derivedMode == MODE_LIST) {
+ thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
mGridView.setAdapter(null);
mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
mListView.setAdapter(mAdapter);
mListView.setChoiceMode(choiceMode);
mCurrentView = mListView;
} else {
- throw new IllegalStateException();
+ throw new IllegalStateException("Unknown state " + state.derivedMode);
}
mThumbSize = new Point(thumbSize, thumbSize);
@@ -271,9 +327,11 @@ public class DirectoryFragment extends Fragment {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final Cursor cursor = mAdapter.getItem(position);
- final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
- if (mFilter.apply(doc)) {
- ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
+ if (cursor != null) {
+ final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
+ if (mFilter.apply(doc)) {
+ ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
+ }
}
}
};
@@ -344,10 +402,20 @@ public class DirectoryFragment extends Fragment {
public void onItemCheckedStateChanged(
ActionMode mode, int position, long id, boolean checked) {
if (checked) {
- // Directories cannot be checked
+ // Directories and footer items cannot be checked
+ boolean valid = false;
+
final Cursor cursor = mAdapter.getItem(position);
- final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
- if (Document.MIME_TYPE_DIR.equals(docMimeType)) {
+ if (cursor != null) {
+ final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+
+ // Only valid if non-directory matches filter
+ final State state = getDisplayState(DirectoryFragment.this);
+ valid = !Document.MIME_TYPE_DIR.equals(docMimeType)
+ && MimePredicate.mimeMatches(state.acceptMimes, docMimeType);
+ }
+
+ if (!valid) {
mCurrentView.setItemChecked(position, false);
}
}
@@ -366,7 +434,7 @@ public class DirectoryFragment extends Fragment {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType(doc.mimeType);
- intent.putExtra(Intent.EXTRA_STREAM, doc.uri);
+ intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
} else if (docs.size() > 1) {
intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
@@ -377,7 +445,7 @@ public class DirectoryFragment extends Fragment {
final ArrayList<Uri> uris = Lists.newArrayList();
for (DocumentInfo doc : docs) {
mimeTypes.add(doc.mimeType);
- uris.add(doc.uri);
+ uris.add(doc.derivedUri);
}
intent.setType(findCommonMimeType(mimeTypes));
@@ -403,7 +471,7 @@ public class DirectoryFragment extends Fragment {
continue;
}
- if (!DocumentsContract.deleteDocument(resolver, doc.uri)) {
+ if (!DocumentsContract.deleteDocument(resolver, doc.derivedUri)) {
Log.w(TAG, "Failed to delete " + doc);
hadTrouble = true;
}
@@ -418,11 +486,25 @@ public class DirectoryFragment extends Fragment {
return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
}
- private interface Footer {
- public View getView(View convertView, ViewGroup parent);
+ private static abstract class Footer {
+ private final int mItemViewType;
+
+ public Footer(int itemViewType) {
+ mItemViewType = itemViewType;
+ }
+
+ public abstract View getView(View convertView, ViewGroup parent);
+
+ public int getItemViewType() {
+ return mItemViewType;
+ }
}
- private static class LoadingFooter implements Footer {
+ private static class LoadingFooter extends Footer {
+ public LoadingFooter() {
+ super(1);
+ }
+
@Override
public View getView(View convertView, ViewGroup parent) {
final Context context = parent.getContext();
@@ -434,11 +516,12 @@ public class DirectoryFragment extends Fragment {
}
}
- private class MessageFooter implements Footer {
+ private class MessageFooter extends Footer {
private final int mIcon;
private final String mMessage;
- public MessageFooter(int icon, String message) {
+ public MessageFooter(int itemViewType, int icon, String message) {
+ super(itemViewType);
mIcon = icon;
mMessage = message;
}
@@ -450,9 +533,9 @@ public class DirectoryFragment extends Fragment {
if (convertView == null) {
final LayoutInflater inflater = LayoutInflater.from(context);
- if (state.mode == MODE_LIST) {
+ if (state.derivedMode == MODE_LIST) {
convertView = inflater.inflate(R.layout.item_message_list, parent, false);
- } else if (state.mode == MODE_GRID) {
+ } else if (state.derivedMode == MODE_GRID) {
convertView = inflater.inflate(R.layout.item_message_grid, parent, false);
} else {
throw new IllegalStateException();
@@ -483,11 +566,11 @@ public class DirectoryFragment extends Fragment {
if (extras != null) {
final String info = extras.getString(DocumentsContract.EXTRA_INFO);
if (info != null) {
- mFooters.add(new MessageFooter(R.drawable.ic_dialog_alert, info));
+ mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_alert, info));
}
final String error = extras.getString(DocumentsContract.EXTRA_ERROR);
if (error != null) {
- mFooters.add(new MessageFooter(R.drawable.ic_dialog_alert, error));
+ mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, error));
}
if (extras.getBoolean(DocumentsContract.EXTRA_LOADING, false)) {
mFooters.add(new LoadingFooter());
@@ -509,7 +592,11 @@ public class DirectoryFragment extends Fragment {
return getDocumentView(position, convertView, parent);
} else {
position -= mCursorCount;
- return mFooters.get(position).getView(convertView, parent);
+ convertView = mFooters.get(position).getView(convertView, parent);
+ // Only the view itself is disabled; contents inside shouldn't
+ // be dimmed.
+ convertView.setEnabled(false);
+ return convertView;
}
}
@@ -523,9 +610,9 @@ public class DirectoryFragment extends Fragment {
if (convertView == null) {
final LayoutInflater inflater = LayoutInflater.from(context);
- if (state.mode == MODE_LIST) {
+ if (state.derivedMode == MODE_LIST) {
convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
- } else if (state.mode == MODE_GRID) {
+ } else if (state.derivedMode == MODE_GRID) {
convertView = inflater.inflate(R.layout.item_doc_grid, parent, false);
} else {
throw new IllegalStateException();
@@ -558,7 +645,11 @@ public class DirectoryFragment extends Fragment {
oldTask.cancel(false);
}
- if ((docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0) {
+ final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
+ final boolean allowThumbnail = (state.derivedMode == MODE_GRID)
+ || MimePredicate.mimeMatches(LIST_THUMBNAIL_MIMES, docMimeType);
+
+ if (supportsThumbnail && allowThumbnail) {
final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
final Bitmap cachedResult = thumbs.get(uri);
if (cachedResult != null) {
@@ -567,7 +658,7 @@ public class DirectoryFragment extends Fragment {
final ThumbnailAsyncTask task = new ThumbnailAsyncTask(icon, mThumbSize);
icon.setImageBitmap(null);
icon.setTag(task);
- task.execute(uri);
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, uri);
}
} else if (docIcon != 0) {
icon.setImageDrawable(IconUtils.loadPackageIcon(context, docAuthority, docIcon));
@@ -619,6 +710,18 @@ public class DirectoryFragment extends Fragment {
line2.setVisibility(hasLine2 ? View.VISIBLE : View.GONE);
+ final boolean enabled = Document.MIME_TYPE_DIR.equals(docMimeType)
+ || MimePredicate.mimeMatches(state.acceptMimes, docMimeType);
+ if (enabled) {
+ setEnabledRecursive(convertView, true);
+ icon.setAlpha(1f);
+ icon1.setAlpha(1f);
+ } else {
+ setEnabledRecursive(convertView, false);
+ icon.setAlpha(0.5f);
+ icon1.setAlpha(0.5f);
+ }
+
return convertView;
}
@@ -643,23 +746,19 @@ public class DirectoryFragment extends Fragment {
}
@Override
+ public int getViewTypeCount() {
+ return 4;
+ }
+
+ @Override
public int getItemViewType(int position) {
if (position < mCursorCount) {
return 0;
} else {
- return IGNORE_ITEM_VIEW_TYPE;
+ position -= mCursorCount;
+ return mFooters.get(position).getItemViewType();
}
}
-
- @Override
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- @Override
- public boolean isEnabled(int position) {
- return position < mCursorCount;
- }
}
private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> {
@@ -749,4 +848,16 @@ public class DirectoryFragment extends Fragment {
return commonType[0] + "/" + commonType[1];
}
+
+ private void setEnabledRecursive(View v, boolean enabled) {
+ if (v.isEnabled() == enabled) return;
+ v.setEnabled(enabled);
+
+ if (v instanceof ViewGroup) {
+ final ViewGroup vg = (ViewGroup) v;
+ for (int i = vg.getChildCount() - 1; i >= 0; i--) {
+ setEnabledRecursive(vg.getChildAt(i), enabled);
+ }
+ }
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 6ea57d7..1471836 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,18 +16,29 @@
package com.android.documentsui;
+import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import android.content.AsyncTaskLoader;
import android.content.ContentProviderClient;
+import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.RecentsProvider.StateColumns;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.RootInfo;
import libcore.io.IoUtils;
@@ -36,6 +47,9 @@ class DirectoryResult implements AutoCloseable {
Cursor cursor;
Exception exception;
+ int mode = MODE_UNKNOWN;
+ int sortOrder = SORT_ORDER_UNKNOWN;
+
@Override
public void close() {
IoUtils.closeQuietly(cursor);
@@ -48,18 +62,21 @@ class DirectoryResult implements AutoCloseable {
public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
- private final String mRootId;
+ private final RootInfo mRoot;
+ private final DocumentInfo mDoc;
private final Uri mUri;
- private final int mSortOrder;
+ private final int mUserSortOrder;
private CancellationSignal mSignal;
private DirectoryResult mResult;
- public DirectoryLoader(Context context, String rootId, Uri uri, int sortOrder) {
+ public DirectoryLoader(
+ Context context, RootInfo root, DocumentInfo doc, Uri uri, int userSortOrder) {
super(context);
- mRootId = rootId;
+ mRoot = root;
+ mDoc = doc;
mUri = uri;
- mSortOrder = sortOrder;
+ mUserSortOrder = userSortOrder;
}
@Override
@@ -70,20 +87,63 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
}
mSignal = new CancellationSignal();
}
- final DirectoryResult result = new DirectoryResult();
+
+ final ContentResolver resolver = getContext().getContentResolver();
final String authority = mUri.getAuthority();
+
+ final DirectoryResult result = new DirectoryResult();
+
+ int userMode = State.MODE_UNKNOWN;
+
+ // Pick up any custom modes requested by user
+ Cursor cursor = null;
try {
- result.client = getContext()
- .getContentResolver().acquireUnstableContentProviderClient(authority);
- final Cursor cursor = result.client.query(
- mUri, null, null, null, getQuerySortOrder(mSortOrder), mSignal);
+ final Uri stateUri = RecentsProvider.buildState(
+ mRoot.authority, mRoot.rootId, mDoc.documentId);
+ cursor = resolver.query(stateUri, null, null, null, null);
+ if (cursor.moveToFirst()) {
+ userMode = getCursorInt(cursor, StateColumns.MODE);
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ if (userMode != State.MODE_UNKNOWN) {
+ result.mode = userMode;
+ } else {
+ if ((mDoc.flags & Document.FLAG_DIR_PREFERS_GRID) != 0) {
+ result.mode = State.MODE_GRID;
+ } else {
+ result.mode = State.MODE_LIST;
+ }
+ }
+
+ if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
+ result.sortOrder = mUserSortOrder;
+ } else {
+ if ((mDoc.flags & Document.FLAG_DIR_PREFERS_LAST_MODIFIED) != 0) {
+ result.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
+ } else {
+ result.sortOrder = State.SORT_ORDER_DISPLAY_NAME;
+ }
+ }
+
+ Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + mUserSortOrder + " --> mode="
+ + result.mode + ", sortOrder=" + result.sortOrder);
+
+ try {
+ result.client = resolver.acquireUnstableContentProviderClient(authority);
+ cursor = result.client.query(
+ mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
cursor.registerContentObserver(mObserver);
- final Cursor withRoot = new RootCursorWrapper(mUri.getAuthority(), mRootId, cursor, -1);
- final Cursor sorted = new SortingCursorWrapper(withRoot, mSortOrder);
+ final Cursor withRoot = new RootCursorWrapper(
+ mUri.getAuthority(), mRoot.rootId, cursor, -1);
+ final Cursor sorted = new SortingCursorWrapper(withRoot, result.sortOrder);
result.cursor = sorted;
} catch (Exception e) {
+ Log.d(TAG, "Failed to query", e);
result.exception = e;
ContentProviderClient.closeQuietly(result.client);
} finally {
@@ -91,6 +151,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
mSignal = null;
}
}
+
return result;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 38b2ee8..79d2443 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -60,6 +60,9 @@ import android.widget.SearchView.OnQueryTextListener;
import android.widget.TextView;
import android.widget.Toast;
+import com.android.documentsui.RecentsProvider.RecentColumns;
+import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
@@ -168,10 +171,6 @@ public class DocumentsActivity extends Activity {
mState.showAdvanced = SettingsActivity.getDisplayAdvancedDevices(this);
if (mState.action == ACTION_MANAGE) {
- mState.sortOrder = SORT_ORDER_LAST_MODIFIED;
- }
-
- if (mState.action == ACTION_MANAGE) {
final Uri uri = intent.getData();
final String rootId = DocumentsContract.getRootId(uri);
final RootInfo root = mRoots.getRoot(uri.getAuthority(), rootId);
@@ -191,7 +190,7 @@ public class DocumentsActivity extends Activity {
try {
if (cursor.moveToFirst()) {
final byte[] rawStack = cursor.getBlob(
- cursor.getColumnIndex(RecentsProvider.COL_PATH));
+ cursor.getColumnIndex(ResumeColumns.STACK));
DurableUtils.readFromArray(rawStack, mState.stack);
}
} catch (IOException e) {
@@ -204,7 +203,7 @@ public class DocumentsActivity extends Activity {
final RootInfo root = getCurrentRoot();
final List<RootInfo> matchingRoots = mRoots.getMatchingRoots(mState);
if (!matchingRoots.contains(root)) {
- mState.stack.clear();
+ mState.stack.reset();
}
// Only open drawer when showing recents
@@ -343,11 +342,16 @@ public class DocumentsActivity extends Activity {
final MenuItem list = menu.findItem(R.id.menu_list);
final MenuItem settings = menu.findItem(R.id.menu_settings);
- grid.setVisible(mState.mode != MODE_GRID);
- list.setVisible(mState.mode != MODE_LIST);
+ if (cwd != null) {
+ sort.setVisible(true);
+ grid.setVisible(mState.derivedMode != MODE_GRID);
+ list.setVisible(mState.derivedMode != MODE_LIST);
+ } else {
+ sort.setVisible(false);
+ grid.setVisible(false);
+ list.setVisible(false);
+ }
- // No sorting in recents
- sort.setVisible(cwd != null);
// Only sort by size when visible
sortSize.setVisible(mState.showSize);
@@ -392,28 +396,19 @@ public class DocumentsActivity extends Activity {
} else if (id == R.id.menu_search) {
return false;
} else if (id == R.id.menu_sort_name) {
- mState.sortOrder = State.SORT_ORDER_DISPLAY_NAME;
- updateDisplayState();
+ setUserSortOrder(State.SORT_ORDER_DISPLAY_NAME);
return true;
} else if (id == R.id.menu_sort_date) {
- mState.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
- updateDisplayState();
+ setUserSortOrder(State.SORT_ORDER_LAST_MODIFIED);
return true;
} else if (id == R.id.menu_sort_size) {
- mState.sortOrder = State.SORT_ORDER_SIZE;
- updateDisplayState();
+ setUserSortOrder(State.SORT_ORDER_SIZE);
return true;
} else if (id == R.id.menu_grid) {
- // TODO: persist explicit user mode for cwd
- mState.mode = MODE_GRID;
- updateDisplayState();
- invalidateOptionsMenu();
+ setUserMode(State.MODE_GRID);
return true;
} else if (id == R.id.menu_list) {
- // TODO: persist explicit user mode for cwd
- mState.mode = MODE_LIST;
- updateDisplayState();
- invalidateOptionsMenu();
+ setUserMode(State.MODE_LIST);
return true;
} else if (id == R.id.menu_settings) {
startActivity(new Intent(this, SettingsActivity.class));
@@ -423,8 +418,36 @@ public class DocumentsActivity extends Activity {
}
}
+ /**
+ * Update UI to reflect internal state changes not from user.
+ */
+ public void onStateChanged() {
+ invalidateOptionsMenu();
+ }
+
+ /**
+ * Set state sort order based on explicit user action.
+ */
+ private void setUserSortOrder(int sortOrder) {
+ mState.userSortOrder = sortOrder;
+ DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
+ }
+
+ /**
+ * Set state mode based on explicit user action.
+ */
+ private void setUserMode(int mode) {
+ mState.userMode = mode;
+ DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
+ }
+
@Override
public void onBackPressed() {
+ if (!mState.stackTouched) {
+ super.onBackPressed();
+ return;
+ }
+
final int size = mState.stack.size();
if (size > 1) {
mState.stack.pop();
@@ -520,6 +543,7 @@ public class DocumentsActivity extends Activity {
}
while (mState.stack.size() > itemPosition + 1) {
+ mState.stackTouched = true;
mState.stack.pop();
}
onCurrentDirectoryChanged();
@@ -528,8 +552,8 @@ public class DocumentsActivity extends Activity {
};
public RootInfo getCurrentRoot() {
- if (mState.stack.size() > 0) {
- return mState.stack.getRoot(mRoots);
+ if (mState.stack.root != null) {
+ return mState.stack.root;
} else {
return mRoots.getRecentsRoot();
}
@@ -545,6 +569,7 @@ public class DocumentsActivity extends Activity {
private void onCurrentDirectoryChanged() {
final FragmentManager fm = getFragmentManager();
+ final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
if (cwd == null) {
@@ -557,10 +582,10 @@ public class DocumentsActivity extends Activity {
} else {
if (mState.currentSearch != null) {
// Ongoing search
- DirectoryFragment.showSearch(fm, cwd.uri, mState.currentSearch);
+ DirectoryFragment.showSearch(fm, root, cwd, mState.currentSearch);
} else {
// Normal boring directory
- DirectoryFragment.showNormal(fm, cwd.uri);
+ DirectoryFragment.showNormal(fm, root, cwd);
}
}
@@ -582,19 +607,17 @@ public class DocumentsActivity extends Activity {
dumpStack();
}
- private void updateDisplayState() {
- // TODO: handle multiple directory stacks on tablets
- DirectoryFragment.get(getFragmentManager()).updateDisplayState();
- }
-
public void onStackPicked(DocumentStack stack) {
mState.stack = stack;
+ mState.stackTouched = true;
onCurrentDirectoryChanged();
}
public void onRootPicked(RootInfo root, boolean closeDrawer) {
// Clear entire backstack and start in new root
+ mState.stack.root = root;
mState.stack.clear();
+ mState.stackTouched = true;
if (!mRoots.isRecentsRoot(root)) {
try {
@@ -623,17 +646,12 @@ public class DocumentsActivity extends Activity {
public void onDocumentPicked(DocumentInfo doc) {
final FragmentManager fm = getFragmentManager();
if (doc.isDirectory()) {
- // TODO: query display mode user preference for this dir
- if (doc.isGridPreferred()) {
- mState.mode = MODE_GRID;
- } else {
- mState.mode = MODE_LIST;
- }
mState.stack.push(doc);
+ mState.stackTouched = true;
onCurrentDirectoryChanged();
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
// Explicit file picked, return
- onFinished(doc.uri);
+ onFinished(doc.derivedUri);
} else if (mState.action == ACTION_CREATE) {
// Replace selected file
SaveFragment.get(fm).setReplaceTarget(doc);
@@ -641,7 +659,7 @@ public class DocumentsActivity extends Activity {
// First try managing the document; we expect manager to filter
// based on authority, so we don't grant.
final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
- manage.setData(doc.uri);
+ manage.setData(doc.derivedUri);
try {
startActivity(manage);
@@ -649,7 +667,7 @@ public class DocumentsActivity extends Activity {
// Fall back to viewing
final Intent view = new Intent(Intent.ACTION_VIEW);
view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- view.setData(doc.uri);
+ view.setData(doc.derivedUri);
try {
startActivity(view);
@@ -665,22 +683,21 @@ public class DocumentsActivity extends Activity {
final int size = docs.size();
final Uri[] uris = new Uri[size];
for (int i = 0; i < size; i++) {
- uris[i] = docs.get(i).uri;
+ uris[i] = docs.get(i).derivedUri;
}
onFinished(uris);
}
}
public void onSaveRequested(DocumentInfo replaceTarget) {
- onFinished(replaceTarget.uri);
+ onFinished(replaceTarget.derivedUri);
}
public void onSaveRequested(String mimeType, String displayName) {
final DocumentInfo cwd = getCurrentDirectory();
- final String authority = cwd.uri.getAuthority();
final Uri childUri = DocumentsContract.createDocument(
- getContentResolver(), cwd.uri, mimeType, displayName);
+ getContentResolver(), cwd.derivedUri, mimeType, displayName);
if (childUri != null) {
onFinished(childUri);
} else {
@@ -698,22 +715,14 @@ public class DocumentsActivity extends Activity {
if (mState.action == ACTION_CREATE) {
// Remember stack for last create
values.clear();
- values.put(RecentsProvider.COL_PATH, rawStack);
- resolver.insert(RecentsProvider.buildRecentCreate(), values);
-
- } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
- // Remember opened items
- for (Uri uri : uris) {
- values.clear();
- values.put(RecentsProvider.COL_URI, uri.toString());
- resolver.insert(RecentsProvider.buildRecentOpen(), values);
- }
+ values.put(RecentColumns.STACK, rawStack);
+ resolver.insert(RecentsProvider.buildRecent(), values);
}
// Remember location for next app launch
final String packageName = getCallingPackage();
values.clear();
- values.put(RecentsProvider.COL_PATH, rawStack);
+ values.put(ResumeColumns.STACK, rawStack);
resolver.insert(RecentsProvider.buildResume(packageName), values);
final Intent intent = new Intent();
@@ -742,13 +751,23 @@ public class DocumentsActivity extends Activity {
public static class State implements android.os.Parcelable {
public int action;
- public int mode = MODE_LIST;
public String[] acceptMimes;
- public int sortOrder = SORT_ORDER_DISPLAY_NAME;
+
+ /** Explicit user choice */
+ public int userMode = MODE_UNKNOWN;
+ /** Derived after loader */
+ public int derivedMode = MODE_LIST;
+
+ /** Explicit user choice */
+ public int userSortOrder = SORT_ORDER_UNKNOWN;
+ /** Derived after loader */
+ public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
+
public boolean allowMultiple = false;
public boolean showSize = false;
public boolean localOnly = false;
public boolean showAdvanced = false;
+ public boolean stackTouched = false;
/** Current user navigation stack; empty implies recents. */
public DocumentStack stack = new DocumentStack();
@@ -760,12 +779,14 @@ public class DocumentsActivity extends Activity {
public static final int ACTION_GET_CONTENT = 3;
public static final int ACTION_MANAGE = 4;
- public static final int MODE_LIST = 0;
- public static final int MODE_GRID = 1;
+ public static final int MODE_UNKNOWN = 0;
+ public static final int MODE_LIST = 1;
+ public static final int MODE_GRID = 2;
- public static final int SORT_ORDER_DISPLAY_NAME = 0;
- public static final int SORT_ORDER_LAST_MODIFIED = 1;
- public static final int SORT_ORDER_SIZE = 2;
+ public static final int SORT_ORDER_UNKNOWN = 0;
+ public static final int SORT_ORDER_DISPLAY_NAME = 1;
+ public static final int SORT_ORDER_LAST_MODIFIED = 2;
+ public static final int SORT_ORDER_SIZE = 3;
@Override
public int describeContents() {
@@ -775,13 +796,14 @@ public class DocumentsActivity extends Activity {
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(action);
- out.writeInt(mode);
+ out.writeInt(userMode);
out.writeStringArray(acceptMimes);
- out.writeInt(sortOrder);
+ out.writeInt(userSortOrder);
out.writeInt(allowMultiple ? 1 : 0);
out.writeInt(showSize ? 1 : 0);
out.writeInt(localOnly ? 1 : 0);
out.writeInt(showAdvanced ? 1 : 0);
+ out.writeInt(stackTouched ? 1 : 0);
DurableUtils.writeToParcel(out, stack);
out.writeString(currentSearch);
}
@@ -791,13 +813,14 @@ public class DocumentsActivity extends Activity {
public State createFromParcel(Parcel in) {
final State state = new State();
state.action = in.readInt();
- state.mode = in.readInt();
+ state.userMode = in.readInt();
state.acceptMimes = in.readStringArray();
- state.sortOrder = in.readInt();
+ state.userSortOrder = in.readInt();
state.allowMultiple = in.readInt() != 0;
state.showSize = in.readInt() != 0;
state.localOnly = in.readInt() != 0;
state.showAdvanced = in.readInt() != 0;
+ state.stackTouched = in.readInt() != 0;
DurableUtils.readFromParcel(in, state.stack);
state.currentSearch = in.readString();
return state;
@@ -811,9 +834,10 @@ public class DocumentsActivity extends Activity {
}
private void dumpStack() {
- Log.d(TAG, "Current stack:");
+ Log.d(TAG, "Current stack: ");
+ Log.d(TAG, " * " + mState.stack.root);
for (DocumentInfo doc : mState.stack) {
- Log.d(TAG, "--> " + doc);
+ Log.d(TAG, " +-- " + doc);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
new file mode 100644
index 0000000..60f0103
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+
+import android.database.AbstractCursor;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+/**
+ * Cursor wrapper that filters MIME types not matching given list.
+ */
+public class FilteringCursorWrapper extends AbstractCursor {
+ private final Cursor mCursor;
+
+ private final int[] mPosition;
+ private int mCount;
+
+ public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes) {
+ mCursor = cursor;
+
+ final int count = cursor.getCount();
+ mPosition = new int[count];
+
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ final String mimeType = cursor.getString(
+ cursor.getColumnIndex(Document.COLUMN_MIME_TYPE));
+ if (MimePredicate.mimeMatches(acceptMimes, mimeType)) {
+ mPosition[mCount++] = cursor.getPosition();
+ }
+ }
+
+ Log.d(TAG, "Before filtering " + cursor.getCount() + ", after " + mCount);
+ }
+
+ @Override
+ public Bundle getExtras() {
+ return mCursor.getExtras();
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ mCursor.close();
+ }
+
+ @Override
+ public boolean onMove(int oldPosition, int newPosition) {
+ return mCursor.moveToPosition(mPosition[newPosition]);
+ }
+
+ @Override
+ public String[] getColumnNames() {
+ return mCursor.getColumnNames();
+ }
+
+ @Override
+ public int getCount() {
+ return mCount;
+ }
+
+ @Override
+ public double getDouble(int column) {
+ return mCursor.getDouble(column);
+ }
+
+ @Override
+ public float getFloat(int column) {
+ return mCursor.getFloat(column);
+ }
+
+ @Override
+ public int getInt(int column) {
+ return mCursor.getInt(column);
+ }
+
+ @Override
+ public long getLong(int column) {
+ return mCursor.getLong(column);
+ }
+
+ @Override
+ public short getShort(int column) {
+ return mCursor.getShort(column);
+ }
+
+ @Override
+ public String getString(int column) {
+ return mCursor.getString(column);
+ }
+
+ @Override
+ public int getType(int column) {
+ return mCursor.getType(column);
+ }
+
+ @Override
+ public boolean isNull(int column) {
+ return mCursor.isNull(column);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index 85d0988..b55ce82 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -49,6 +49,18 @@ public class MimePredicate implements Predicate<DocumentInfo> {
return false;
}
+ public static boolean mimeMatches(String filter, String[] tests) {
+ if (tests == null) {
+ return true;
+ }
+ for (String test : tests) {
+ if (mimeMatches(filter, test)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public static boolean mimeMatches(String[] filters, String test) {
if (filters == null) {
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 756a297..57442a0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -17,6 +17,9 @@
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
+import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
import android.content.AsyncTaskLoader;
import android.content.ContentProviderClient;
@@ -79,6 +82,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
}
private final List<RootInfo> mRoots;
+ private final String[] mAcceptMimes;
private final HashMap<RootInfo, RecentTask> mTasks = Maps.newHashMap();
@@ -135,9 +139,10 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
}
}
- public RecentLoader(Context context, List<RootInfo> roots) {
+ public RecentLoader(Context context, List<RootInfo> roots, String[] acceptMimes) {
super(context);
mRoots = roots;
+ mAcceptMimes = acceptMimes;
}
@Override
@@ -171,7 +176,15 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
for (RecentTask task : mTasks.values()) {
if (task.isDone()) {
try {
- cursors.add(task.get());
+ final Cursor cursor = task.get();
+ final FilteringCursorWrapper filtered = new FilteringCursorWrapper(
+ cursor, mAcceptMimes) {
+ @Override
+ public void close() {
+ // Ignored, since we manage cursor lifecycle internally
+ }
+ };
+ cursors.add(filtered);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
@@ -181,15 +194,14 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
}
final DirectoryResult result = new DirectoryResult();
+
+ final boolean acceptImages = MimePredicate.mimeMatches("image/*", mAcceptMimes);
+ result.mode = acceptImages ? MODE_GRID : MODE_LIST;
+ result.sortOrder = SORT_ORDER_LAST_MODIFIED;
+
if (cursors.size() > 0) {
final MergeCursor merged = new MergeCursor(cursors.toArray(new Cursor[cursors.size()]));
- final SortingCursorWrapper sorted = new SortingCursorWrapper(
- merged, State.SORT_ORDER_LAST_MODIFIED) {
- @Override
- public void close() {
- // Ignored, since we manage cursor lifecycle internally
- }
- };
+ final SortingCursorWrapper sorted = new SortingCursorWrapper(merged, result.sortOrder);
result.cursor = sorted;
}
return result;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 461c415..3642478 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -26,10 +26,14 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Loader;
import android.database.Cursor;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
import android.text.TextUtils.TruncateAt;
+import android.text.style.ImageSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -41,8 +45,8 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
+import com.android.documentsui.RecentsProvider.RecentColumns;
import com.android.documentsui.model.DocumentStack;
-import com.android.documentsui.model.RootInfo;
import com.google.android.collect.Lists;
import libcore.io.IoUtils;
@@ -128,7 +132,7 @@ public class RecentsCreateFragment extends Fragment {
public static class RecentsCreateLoader extends UriDerivativeLoader<Uri, List<DocumentStack>> {
public RecentsCreateLoader(Context context) {
- super(context, RecentsProvider.buildRecentCreate());
+ super(context, RecentsProvider.buildRecent());
}
@Override
@@ -137,14 +141,14 @@ public class RecentsCreateFragment extends Fragment {
final ContentResolver resolver = getContext().getContentResolver();
final Cursor cursor = resolver.query(
- uri, null, null, null, RecentsProvider.COL_TIMESTAMP + " DESC", signal);
+ uri, null, null, null, RecentColumns.TIMESTAMP + " DESC", signal);
try {
while (cursor != null && cursor.moveToNext()) {
- final byte[] raw = cursor.getBlob(
- cursor.getColumnIndex(RecentsProvider.COL_PATH));
+ final byte[] rawStack = cursor.getBlob(
+ cursor.getColumnIndex(RecentColumns.STACK));
try {
final DocumentStack stack = new DocumentStack();
- stack.read(new DataInputStream(new ByteArrayInputStream(raw)));
+ stack.read(new DataInputStream(new ByteArrayInputStream(rawStack)));
result.add(stack);
} catch (IOException e) {
Log.w(TAG, "Failed to resolve stack: " + e);
@@ -181,21 +185,29 @@ public class RecentsCreateFragment extends Fragment {
final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+ final View line2 = convertView.findViewById(R.id.line2);
final DocumentStack stack = getItem(position);
- final RootInfo root = stack.getRoot(roots);
- icon.setImageDrawable(root.loadIcon(context));
+ icon.setImageDrawable(stack.root.loadIcon(context));
- final StringBuilder builder = new StringBuilder();
- for (int i = stack.size() - 1; i >= 0; i--) {
+ final Drawable crumb = context.getResources()
+ .getDrawable(R.drawable.ic_breadcrumb_arrow);
+ crumb.setBounds(0, 0, crumb.getIntrinsicWidth(), crumb.getIntrinsicHeight());
+
+ final SpannableStringBuilder builder = new SpannableStringBuilder();
+ builder.append(stack.root.title);
+ appendDrawable(builder, crumb);
+ for (int i = stack.size() - 2; i >= 0; i--) {
builder.append(stack.get(i).displayName);
if (i > 0) {
- builder.append(" \u232a ");
+ appendDrawable(builder, crumb);
}
}
- title.setText(builder.toString());
+ title.setText(builder);
title.setEllipsize(TruncateAt.MIDDLE);
+ line2.setVisibility(View.GONE);
+
return convertView;
}
@@ -214,4 +226,10 @@ public class RecentsCreateFragment extends Fragment {
return getItem(position).hashCode();
}
}
+
+ private static void appendDrawable(SpannableStringBuilder b, Drawable d) {
+ final int length = b.length();
+ b.append("\u232a");
+ b.setSpan(new ImageSpan(d), length, b.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 0c87783..1fe5d54 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -25,51 +25,64 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
import android.text.format.DateUtils;
import android.util.Log;
public class RecentsProvider extends ContentProvider {
private static final String TAG = "RecentsProvider";
- // TODO: offer view of recents that handles backend root resolution before
- // returning cursor, include extra columns
+ public static final long MAX_HISTORY_IN_MILLIS = DateUtils.DAY_IN_MILLIS * 45;
- public static final String AUTHORITY = "com.android.documentsui.recents";
+ private static final String AUTHORITY = "com.android.documentsui.recents";
private static final UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- private static final int URI_RECENT_OPEN = 1;
- private static final int URI_RECENT_CREATE = 2;
+ private static final int URI_RECENT = 1;
+ private static final int URI_STATE = 2;
private static final int URI_RESUME = 3;
static {
- sMatcher.addURI(AUTHORITY, "recent_open", URI_RECENT_OPEN);
- sMatcher.addURI(AUTHORITY, "recent_create", URI_RECENT_CREATE);
+ sMatcher.addURI(AUTHORITY, "recent", URI_RECENT);
+ // state/authority/rootId/docId
+ sMatcher.addURI(AUTHORITY, "state/*/*/*", URI_STATE);
+ // resume/packageName
sMatcher.addURI(AUTHORITY, "resume/*", URI_RESUME);
}
- private static final String TABLE_RECENT_OPEN = "recent_open";
- private static final String TABLE_RECENT_CREATE = "recent_create";
- private static final String TABLE_RESUME = "resume";
-
- /**
- * String of URIs pointing at a storage backend, stored as a JSON array,
- * starting with root.
- */
- public static final String COL_PATH = "path";
- public static final String COL_URI = "uri";
- public static final String COL_PACKAGE_NAME = "package_name";
- public static final String COL_TIMESTAMP = "timestamp";
-
- @Deprecated
- public static Uri buildRecentOpen() {
- return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
- .authority(AUTHORITY).appendPath("recent_open").build();
+ public static final String TABLE_RECENT = "recent";
+ public static final String TABLE_STATE = "state";
+ public static final String TABLE_RESUME = "resume";
+
+ public static class RecentColumns {
+ public static final String STACK = "stack";
+ public static final String TIMESTAMP = "timestamp";
+ }
+
+ public static class StateColumns {
+ public static final String AUTHORITY = "authority";
+ public static final String ROOT_ID = Root.COLUMN_ROOT_ID;
+ public static final String DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID;
+ public static final String MODE = "mode";
+ public static final String SORT_ORDER = "sortOrder";
}
- public static Uri buildRecentCreate() {
+ public static class ResumeColumns {
+ public static final String PACKAGE_NAME = "package_name";
+ public static final String STACK = "stack";
+ public static final String TIMESTAMP = "timestamp";
+ }
+
+ public static Uri buildRecent() {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
- .authority(AUTHORITY).appendPath("recent_create").build();
+ .authority(AUTHORITY).appendPath("recent").build();
+ }
+
+ public static Uri buildState(String authority, String rootId, String documentId) {
+ return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
+ .appendPath("state").appendPath(authority).appendPath(rootId).appendPath(documentId)
+ .build();
}
public static Uri buildResume(String packageName) {
@@ -83,35 +96,42 @@ public class RecentsProvider extends ContentProvider {
private static final String DB_NAME = "recents.db";
private static final int VERSION_INIT = 1;
+ private static final int VERSION_AS_BLOB = 3;
public DatabaseHelper(Context context) {
- super(context, DB_NAME, null, VERSION_INIT);
+ super(context, DB_NAME, null, VERSION_AS_BLOB);
}
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_RECENT_OPEN + " (" +
- COL_URI + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
- COL_TIMESTAMP + " INTEGER" +
+
+ db.execSQL("CREATE TABLE " + TABLE_RECENT + " (" +
+ RecentColumns.STACK + " BLOB PRIMARY KEY ON CONFLICT REPLACE," +
+ RecentColumns.TIMESTAMP + " INTEGER" +
")");
- db.execSQL("CREATE TABLE " + TABLE_RECENT_CREATE + " (" +
- COL_PATH + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
- COL_TIMESTAMP + " INTEGER" +
+ db.execSQL("CREATE TABLE " + TABLE_STATE + " (" +
+ StateColumns.AUTHORITY + " TEXT," +
+ StateColumns.ROOT_ID + " TEXT," +
+ StateColumns.DOCUMENT_ID + " TEXT," +
+ StateColumns.MODE + " INTEGER," +
+ StateColumns.SORT_ORDER + " INTEGER," +
+ "PRIMARY KEY (" + StateColumns.AUTHORITY + ", " + StateColumns.ROOT_ID + ", "
+ + StateColumns.DOCUMENT_ID + ")" +
")");
db.execSQL("CREATE TABLE " + TABLE_RESUME + " (" +
- COL_PACKAGE_NAME + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
- COL_PATH + " TEXT," +
- COL_TIMESTAMP + " INTEGER" +
+ ResumeColumns.PACKAGE_NAME + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
+ ResumeColumns.STACK + " BLOB," +
+ ResumeColumns.TIMESTAMP + " INTEGER" +
")");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database; wiping app data");
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECENT_OPEN);
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECENT_CREATE);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECENT);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_STATE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RESUME);
onCreate(db);
}
@@ -128,22 +148,23 @@ public class RecentsProvider extends ContentProvider {
String sortOrder) {
final SQLiteDatabase db = mHelper.getReadableDatabase();
switch (sMatcher.match(uri)) {
- case URI_RECENT_OPEN: {
- return db.query(TABLE_RECENT_OPEN, projection,
- buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null);
- }
- case URI_RECENT_CREATE: {
- return db.query(TABLE_RECENT_CREATE, projection,
- buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null);
- }
- case URI_RESUME: {
+ case URI_RECENT:
+ final long cutoff = System.currentTimeMillis() - MAX_HISTORY_IN_MILLIS;
+ return db.query(TABLE_RECENT, projection, RecentColumns.TIMESTAMP + ">" + cutoff,
+ null, null, null, null);
+ case URI_STATE:
+ final String authority = uri.getPathSegments().get(1);
+ final String rootId = uri.getPathSegments().get(2);
+ final String documentId = uri.getPathSegments().get(3);
+ return db.query(TABLE_STATE, projection, StateColumns.AUTHORITY + "=? AND "
+ + StateColumns.ROOT_ID + "=? AND " + StateColumns.DOCUMENT_ID + "=?",
+ new String[] { authority, rootId, documentId }, null, null, null);
+ case URI_RESUME:
final String packageName = uri.getPathSegments().get(1);
- return db.query(TABLE_RESUME, projection, COL_PACKAGE_NAME + "=?",
+ return db.query(TABLE_RESUME, projection, ResumeColumns.PACKAGE_NAME + "=?",
new String[] { packageName }, null, null, null);
- }
- default: {
+ default:
throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
}
}
@@ -156,28 +177,37 @@ public class RecentsProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db = mHelper.getWritableDatabase();
switch (sMatcher.match(uri)) {
- case URI_RECENT_OPEN: {
- values.put(COL_TIMESTAMP, System.currentTimeMillis());
- db.insert(TABLE_RECENT_OPEN, null, values);
- db.delete(TABLE_RECENT_OPEN, buildWhereOlder(DateUtils.WEEK_IN_MILLIS), null);
+ case URI_RECENT:
+ values.put(RecentColumns.TIMESTAMP, System.currentTimeMillis());
+ db.insert(TABLE_RECENT, null, values);
+ final long cutoff = System.currentTimeMillis() - MAX_HISTORY_IN_MILLIS;
+ db.delete(TABLE_RECENT, RecentColumns.TIMESTAMP + "<" + cutoff, null);
return uri;
- }
- case URI_RECENT_CREATE: {
- values.put(COL_TIMESTAMP, System.currentTimeMillis());
- db.insert(TABLE_RECENT_CREATE, null, values);
- db.delete(TABLE_RECENT_CREATE, buildWhereOlder(DateUtils.WEEK_IN_MILLIS), null);
+ case URI_STATE:
+ final String authority = uri.getPathSegments().get(1);
+ final String rootId = uri.getPathSegments().get(2);
+ final String documentId = uri.getPathSegments().get(3);
+
+ final ContentValues key = new ContentValues();
+ key.put(StateColumns.AUTHORITY, authority);
+ key.put(StateColumns.ROOT_ID, rootId);
+ key.put(StateColumns.DOCUMENT_ID, documentId);
+
+ // Ensure that row exists, then update with changed values
+ db.insertWithOnConflict(TABLE_STATE, null, key, SQLiteDatabase.CONFLICT_IGNORE);
+ db.update(TABLE_STATE, values, StateColumns.AUTHORITY + "=? AND "
+ + StateColumns.ROOT_ID + "=? AND " + StateColumns.DOCUMENT_ID + "=?",
+ new String[] { authority, rootId, documentId });
+
return uri;
- }
- case URI_RESUME: {
+ case URI_RESUME:
final String packageName = uri.getPathSegments().get(1);
- values.put(COL_PACKAGE_NAME, packageName);
- values.put(COL_TIMESTAMP, System.currentTimeMillis());
+ values.put(ResumeColumns.PACKAGE_NAME, packageName);
+ values.put(ResumeColumns.TIMESTAMP, System.currentTimeMillis());
db.insert(TABLE_RESUME, null, values);
return uri;
- }
- default: {
+ default:
throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
}
}
@@ -190,12 +220,4 @@ public class RecentsProvider extends ContentProvider {
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("Unsupported Uri " + uri);
}
-
- private static String buildWhereOlder(long deltaMillis) {
- return COL_TIMESTAMP + "<" + (System.currentTimeMillis() - deltaMillis);
- }
-
- private static String buildWhereYounger(long deltaMillis) {
- return COL_TIMESTAMP + ">" + (System.currentTimeMillis() - deltaMillis);
- }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index d4f1b39..adf4701 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -90,7 +90,6 @@ public class RootsCache {
if (info.metaData != null && info.metaData.containsKey(
DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
- // TODO: remove deprecated customRoots flag
// TODO: populate roots on background thread, and cache results
final Uri rootsUri = DocumentsContract.buildRootsUri(info.authority);
final ContentProviderClient client = resolver
@@ -169,8 +168,9 @@ public class RootsCache {
if (state.localOnly && !localOnly) continue;
// Only include roots that serve requested content
- final boolean overlap = MimePredicate.mimeMatches(root.mimeTypes, state.acceptMimes)
- || MimePredicate.mimeMatches(state.acceptMimes, root.mimeTypes);
+ final boolean overlap =
+ MimePredicate.mimeMatches(root.derivedMimeTypes, state.acceptMimes) ||
+ MimePredicate.mimeMatches(state.acceptMimes, root.derivedMimeTypes);
if (!overlap) {
continue;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index a1489a5..c69103e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -20,6 +20,8 @@ import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
@@ -32,15 +34,16 @@ import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ProtocolException;
-import java.util.Comparator;
/**
* Representation of a {@link Document}.
*/
-public class DocumentInfo implements Durable {
+public class DocumentInfo implements Durable, Parcelable {
private static final int VERSION_INIT = 1;
+ private static final int VERSION_SPLIT_URI = 2;
- public Uri uri;
+ public String authority;
+ public String documentId;
public String mimeType;
public String displayName;
public long lastModified;
@@ -49,13 +52,17 @@ public class DocumentInfo implements Durable {
public long size;
public int icon;
+ /** Derived fields that aren't persisted */
+ public Uri derivedUri;
+
public DocumentInfo() {
reset();
}
@Override
public void reset() {
- uri = null;
+ authority = null;
+ documentId = null;
mimeType = null;
displayName = null;
lastModified = -1;
@@ -63,6 +70,8 @@ public class DocumentInfo implements Durable {
summary = null;
size = -1;
icon = 0;
+
+ derivedUri = null;
}
@Override
@@ -70,8 +79,10 @@ public class DocumentInfo implements Durable {
final int version = in.readInt();
switch (version) {
case VERSION_INIT:
- final String rawUri = DurableUtils.readNullableString(in);
- uri = rawUri != null ? Uri.parse(rawUri) : null;
+ throw new ProtocolException("Ignored upgrade");
+ case VERSION_SPLIT_URI:
+ authority = DurableUtils.readNullableString(in);
+ documentId = DurableUtils.readNullableString(in);
mimeType = DurableUtils.readNullableString(in);
displayName = DurableUtils.readNullableString(in);
lastModified = in.readLong();
@@ -79,6 +90,7 @@ public class DocumentInfo implements Durable {
summary = DurableUtils.readNullableString(in);
size = in.readLong();
icon = in.readInt();
+ deriveFields();
break;
default:
throw new ProtocolException("Unknown version " + version);
@@ -87,8 +99,9 @@ public class DocumentInfo implements Durable {
@Override
public void write(DataOutputStream out) throws IOException {
- out.writeInt(VERSION_INIT);
- DurableUtils.writeNullableString(out, uri.toString());
+ out.writeInt(VERSION_SPLIT_URI);
+ DurableUtils.writeNullableString(out, authority);
+ DurableUtils.writeNullableString(out, documentId);
DurableUtils.writeNullableString(out, mimeType);
DurableUtils.writeNullableString(out, displayName);
out.writeLong(lastModified);
@@ -98,11 +111,41 @@ public class DocumentInfo implements Durable {
out.writeInt(icon);
}
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ DurableUtils.writeToParcel(dest, this);
+ }
+
+ public static final Creator<DocumentInfo> CREATOR = new Creator<DocumentInfo>() {
+ @Override
+ public DocumentInfo createFromParcel(Parcel in) {
+ final DocumentInfo doc = new DocumentInfo();
+ DurableUtils.readFromParcel(in, doc);
+ return doc;
+ }
+
+ @Override
+ public DocumentInfo[] newArray(int size) {
+ return new DocumentInfo[size];
+ }
+ };
+
public static DocumentInfo fromDirectoryCursor(Cursor cursor) {
- final DocumentInfo doc = new DocumentInfo();
final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
- final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
- doc.uri = DocumentsContract.buildDocumentUri(authority, docId);
+ return fromCursor(cursor, authority);
+ }
+
+ public static DocumentInfo fromCursor(Cursor cursor, String authority) {
+ final DocumentInfo doc = new DocumentInfo();
+ doc.authority = authority;
+ doc.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+ doc.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ doc.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
doc.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
doc.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
doc.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
@@ -110,6 +153,7 @@ public class DocumentInfo implements Durable {
doc.summary = getCursorString(cursor, Document.COLUMN_SUMMARY);
doc.size = getCursorLong(cursor, Document.COLUMN_SIZE);
doc.icon = getCursorInt(cursor, Document.COLUMN_ICON);
+ doc.deriveFields();
return doc;
}
@@ -122,16 +166,7 @@ public class DocumentInfo implements Durable {
if (!cursor.moveToFirst()) {
throw new FileNotFoundException("Missing details for " + uri);
}
- final DocumentInfo doc = new DocumentInfo();
- doc.uri = uri;
- doc.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
- doc.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
- doc.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
- doc.flags = getCursorInt(cursor, Document.COLUMN_FLAGS);
- doc.summary = getCursorString(cursor, Document.COLUMN_SUMMARY);
- doc.size = getCursorLong(cursor, Document.COLUMN_SIZE);
- doc.icon = getCursorInt(cursor, Document.COLUMN_ICON);
- return doc;
+ return fromCursor(cursor, uri.getAuthority());
} catch (Throwable t) {
throw asFileNotFoundException(t);
} finally {
@@ -140,9 +175,13 @@ public class DocumentInfo implements Durable {
}
}
+ private void deriveFields() {
+ derivedUri = DocumentsContract.buildDocumentUri(authority, documentId);
+ }
+
@Override
public String toString() {
- return "Document{name=" + displayName + ", uri=" + uri + "}";
+ return "Document{name=" + displayName + ", docId=" + documentId + "}";
}
public boolean isCreateSupported() {
@@ -189,42 +228,14 @@ public class DocumentInfo implements Durable {
}
}
+ /**
+ * Missing or null values are returned as 0.
+ */
public static int getCursorInt(Cursor cursor, String columnName) {
final int index = cursor.getColumnIndex(columnName);
return (index != -1) ? cursor.getInt(index) : 0;
}
- @Deprecated
- public static class DisplayNameComparator implements Comparator<DocumentInfo> {
- @Override
- public int compare(DocumentInfo lhs, DocumentInfo rhs) {
- final boolean leftDir = lhs.isDirectory();
- final boolean rightDir = rhs.isDirectory();
-
- if (leftDir != rightDir) {
- return leftDir ? -1 : 1;
- } else {
- return compareToIgnoreCaseNullable(lhs.displayName, rhs.displayName);
- }
- }
- }
-
- @Deprecated
- public static class LastModifiedComparator implements Comparator<DocumentInfo> {
- @Override
- public int compare(DocumentInfo lhs, DocumentInfo rhs) {
- return Long.compare(rhs.lastModified, lhs.lastModified);
- }
- }
-
- @Deprecated
- public static class SizeComparator implements Comparator<DocumentInfo> {
- @Override
- public int compare(DocumentInfo lhs, DocumentInfo rhs) {
- return Long.compare(rhs.size, lhs.size);
- }
- }
-
public static FileNotFoundException asFileNotFoundException(Throwable t)
throws FileNotFoundException {
if (t instanceof FileNotFoundException) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
index 33a1376..2541440 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
@@ -16,8 +16,6 @@
package com.android.documentsui.model;
-import com.android.documentsui.RootsCache;
-
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -30,14 +28,13 @@ import java.util.LinkedList;
*/
public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
private static final int VERSION_INIT = 1;
+ private static final int VERSION_ADD_ROOT = 2;
- public RootInfo getRoot(RootsCache roots) {
- return roots.findRoot(getLast().uri);
- }
+ public RootInfo root;
- public String getTitle(RootsCache roots) {
- if (size() == 1) {
- return getRoot(roots).title;
+ public String getTitle() {
+ if (size() == 1 && root != null) {
+ return root.title;
} else if (size() > 1) {
return peek().displayName;
} else {
@@ -52,6 +49,7 @@ public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
@Override
public void reset() {
clear();
+ root = null;
}
@Override
@@ -59,6 +57,12 @@ public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
final int version = in.readInt();
switch (version) {
case VERSION_INIT:
+ throw new ProtocolException("Ignored upgrade");
+ case VERSION_ADD_ROOT:
+ if (in.readBoolean()) {
+ root = new RootInfo();
+ root.read(in);
+ }
final int size = in.readInt();
for (int i = 0; i < size; i++) {
final DocumentInfo doc = new DocumentInfo();
@@ -73,7 +77,13 @@ public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
@Override
public void write(DataOutputStream out) throws IOException {
- out.writeInt(VERSION_INIT);
+ out.writeInt(VERSION_ADD_ROOT);
+ if (root != null) {
+ out.writeBoolean(true);
+ root.write(out);
+ } else {
+ out.writeBoolean(false);
+ }
final int size = size();
out.writeInt(size);
for (int i = 0; i < size; i++) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index a6ddf70..e0e8acf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -23,28 +23,121 @@ import static com.android.documentsui.model.DocumentInfo.getCursorString;
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.provider.DocumentsContract.Root;
import com.android.documentsui.IconUtils;
import com.android.documentsui.R;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.ProtocolException;
import java.util.Objects;
/**
* Representation of a {@link Root}.
*/
-public class RootInfo {
+public class RootInfo implements Durable, Parcelable {
+ private static final int VERSION_INIT = 1;
+
public String authority;
public String rootId;
public int rootType;
public int flags;
public int icon;
- public int localIcon;
public String title;
public String summary;
public String documentId;
public long availableBytes;
- public String[] mimeTypes;
+ public String mimeTypes;
+
+ /** Derived fields that aren't persisted */
+ public String[] derivedMimeTypes;
+ public int derivedIcon;
+
+ public RootInfo() {
+ reset();
+ }
+
+ @Override
+ public void reset() {
+ authority = null;
+ rootId = null;
+ rootType = 0;
+ flags = 0;
+ icon = 0;
+ title = null;
+ summary = null;
+ documentId = null;
+ availableBytes = -1;
+ mimeTypes = null;
+
+ derivedMimeTypes = null;
+ derivedIcon = 0;
+ }
+
+ @Override
+ public void read(DataInputStream in) throws IOException {
+ final int version = in.readInt();
+ switch (version) {
+ case VERSION_INIT:
+ authority = DurableUtils.readNullableString(in);
+ rootId = DurableUtils.readNullableString(in);
+ rootType = in.readInt();
+ flags = in.readInt();
+ icon = in.readInt();
+ title = DurableUtils.readNullableString(in);
+ summary = DurableUtils.readNullableString(in);
+ documentId = DurableUtils.readNullableString(in);
+ availableBytes = in.readLong();
+ mimeTypes = DurableUtils.readNullableString(in);
+ deriveFields();
+ break;
+ default:
+ throw new ProtocolException("Unknown version " + version);
+ }
+ }
+
+ @Override
+ public void write(DataOutputStream out) throws IOException {
+ out.writeInt(VERSION_INIT);
+ DurableUtils.writeNullableString(out, authority);
+ DurableUtils.writeNullableString(out, rootId);
+ out.writeInt(rootType);
+ out.writeInt(flags);
+ out.writeInt(icon);
+ DurableUtils.writeNullableString(out, title);
+ DurableUtils.writeNullableString(out, summary);
+ DurableUtils.writeNullableString(out, documentId);
+ out.writeLong(availableBytes);
+ DurableUtils.writeNullableString(out, mimeTypes);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ DurableUtils.writeToParcel(dest, this);
+ }
+
+ public static final Creator<RootInfo> CREATOR = new Creator<RootInfo>() {
+ @Override
+ public RootInfo createFromParcel(Parcel in) {
+ final RootInfo root = new RootInfo();
+ DurableUtils.readFromParcel(in, root);
+ return root;
+ }
+
+ @Override
+ public RootInfo[] newArray(int size) {
+ return new RootInfo[size];
+ }
+ };
public static RootInfo fromRootsCursor(String authority, Cursor cursor) {
final RootInfo root = new RootInfo();
@@ -57,31 +150,38 @@ public class RootInfo {
root.summary = getCursorString(cursor, Root.COLUMN_SUMMARY);
root.documentId = getCursorString(cursor, Root.COLUMN_DOCUMENT_ID);
root.availableBytes = getCursorLong(cursor, Root.COLUMN_AVAILABLE_BYTES);
+ root.mimeTypes = getCursorString(cursor, Root.COLUMN_MIME_TYPES);
+ root.deriveFields();
+ return root;
+ }
- final String raw = getCursorString(cursor, Root.COLUMN_MIME_TYPES);
- root.mimeTypes = (raw != null) ? raw.split("\n") : null;
+ private void deriveFields() {
+ derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
// TODO: remove these special case icons
if ("com.android.externalstorage.documents".equals(authority)) {
- root.localIcon = R.drawable.ic_root_sdcard;
+ derivedIcon = R.drawable.ic_root_sdcard;
}
if ("com.android.providers.downloads.documents".equals(authority)) {
- root.localIcon = R.drawable.ic_root_download;
+ derivedIcon = R.drawable.ic_root_download;
}
if ("com.android.providers.media.documents".equals(authority)) {
- if ("image".equals(root.rootId)) {
- root.localIcon = R.drawable.ic_doc_image;
- } else if ("audio".equals(root.rootId)) {
- root.localIcon = R.drawable.ic_doc_audio;
+ if ("image".equals(rootId)) {
+ derivedIcon = R.drawable.ic_doc_image;
+ } else if ("audio".equals(rootId)) {
+ derivedIcon = R.drawable.ic_doc_audio;
}
}
+ }
- return root;
+ @Override
+ public String toString() {
+ return "Root{title=" + title + ", rootId=" + rootId + "}";
}
public Drawable loadIcon(Context context) {
- if (localIcon != 0) {
- return context.getResources().getDrawable(localIcon);
+ if (derivedIcon != 0) {
+ return context.getResources().getDrawable(derivedIcon);
} else {
return IconUtils.loadPackageIcon(context, authority, icon);
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index f53e60d..cdb6b33 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -30,7 +30,7 @@ public class RootsCacheTest extends AndroidTestCase {
private static RootInfo buildForMimeTypes(String... mimeTypes) {
final RootInfo root = new RootInfo();
- root.mimeTypes = mimeTypes;
+ root.derivedMimeTypes = mimeTypes;
return root;
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 226d635..2326ec2 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -181,12 +181,12 @@ public class ExternalStorageProvider extends DocumentsProvider {
}
final RowBuilder row = result.newRow();
- row.offer(Document.COLUMN_DOCUMENT_ID, docId);
- row.offer(Document.COLUMN_DISPLAY_NAME, displayName);
- row.offer(Document.COLUMN_SIZE, file.length());
- row.offer(Document.COLUMN_MIME_TYPE, mimeType);
- row.offer(Document.COLUMN_LAST_MODIFIED, file.lastModified());
- row.offer(Document.COLUMN_FLAGS, flags);
+ row.add(Document.COLUMN_DOCUMENT_ID, docId);
+ row.add(Document.COLUMN_DISPLAY_NAME, displayName);
+ row.add(Document.COLUMN_SIZE, file.length());
+ row.add(Document.COLUMN_MIME_TYPE, mimeType);
+ row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
+ row.add(Document.COLUMN_FLAGS, flags);
}
@Override
@@ -197,13 +197,13 @@ public class ExternalStorageProvider extends DocumentsProvider {
final File path = mIdToPath.get(rootId);
final RowBuilder row = result.newRow();
- row.offer(Root.COLUMN_ROOT_ID, root.rootId);
- row.offer(Root.COLUMN_ROOT_TYPE, root.rootType);
- row.offer(Root.COLUMN_FLAGS, root.flags);
- row.offer(Root.COLUMN_ICON, root.icon);
- row.offer(Root.COLUMN_TITLE, root.title);
- row.offer(Root.COLUMN_DOCUMENT_ID, root.docId);
- row.offer(Root.COLUMN_AVAILABLE_BYTES, path.getFreeSpace());
+ row.add(Root.COLUMN_ROOT_ID, root.rootId);
+ row.add(Root.COLUMN_ROOT_TYPE, root.rootType);
+ row.add(Root.COLUMN_FLAGS, root.flags);
+ row.add(Root.COLUMN_ICON, root.icon);
+ row.add(Root.COLUMN_TITLE, root.title);
+ row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
+ row.add(Root.COLUMN_AVAILABLE_BYTES, path.getFreeSpace());
}
return result;
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
index 872974f..014c664 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
@@ -69,13 +69,13 @@ public class TestDocumentsProvider extends DocumentsProvider {
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
final RowBuilder row = result.newRow();
- row.offer(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
- row.offer(Root.COLUMN_ROOT_TYPE, Root.ROOT_TYPE_SERVICE);
- row.offer(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS);
- row.offer(Root.COLUMN_TITLE, "_Test title which is really long");
- row.offer(Root.COLUMN_SUMMARY, "_Summary which is also super long text");
- row.offer(Root.COLUMN_DOCUMENT_ID, MY_DOC_ID);
- row.offer(Root.COLUMN_AVAILABLE_BYTES, 1024);
+ row.add(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
+ row.add(Root.COLUMN_ROOT_TYPE, Root.ROOT_TYPE_SERVICE);
+ row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS);
+ row.add(Root.COLUMN_TITLE, "_Test title which is really long");
+ row.add(Root.COLUMN_SUMMARY, "_Summary which is also super long text");
+ row.add(Root.COLUMN_DOCUMENT_ID, MY_DOC_ID);
+ row.add(Root.COLUMN_AVAILABLE_BYTES, 1024);
return result;
}
@@ -125,6 +125,9 @@ public class TestDocumentsProvider extends DocumentsProvider {
includeFile(result, "_networkfile1");
includeFile(result, "_networkfile2");
includeFile(result, "_networkfile3");
+ includeFile(result, "_networkfile4");
+ includeFile(result, "_networkfile5");
+ includeFile(result, "_networkfile6");
return true;
} else {
return false;
@@ -162,6 +165,8 @@ public class TestDocumentsProvider extends DocumentsProvider {
includeFile(result, MY_DOC_NULL);
includeFile(result, "localfile1");
includeFile(result, "localfile2");
+ includeFile(result, "localfile3");
+ includeFile(result, "localfile4");
synchronized (this) {
// Try picking up an existing network fetch
@@ -229,16 +234,16 @@ public class TestDocumentsProvider extends DocumentsProvider {
private static void includeFile(MatrixCursor result, String docId) {
final RowBuilder row = result.newRow();
- row.offer(Document.COLUMN_DOCUMENT_ID, docId);
- row.offer(Document.COLUMN_DISPLAY_NAME, docId);
- row.offer(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis());
+ row.add(Document.COLUMN_DOCUMENT_ID, docId);
+ row.add(Document.COLUMN_DISPLAY_NAME, docId);
+ row.add(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis());
if (MY_DOC_ID.equals(docId)) {
- row.offer(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+ row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
} else if (MY_DOC_NULL.equals(docId)) {
// No MIME type
} else {
- row.offer(Document.COLUMN_MIME_TYPE, "application/octet-stream");
+ row.add(Document.COLUMN_MIME_TYPE, "application/octet-stream");
}
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 78b842c..40a1af6 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -50,6 +50,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.speech.hotword.HotwordRecognitionListener;
+import android.speech.hotword.HotwordRecognitionService;
import android.speech.hotword.HotwordRecognizer;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
@@ -1775,11 +1776,13 @@ public class KeyguardHostView extends KeyguardViewBase {
public void onHotwordEvent(int eventType, Bundle eventBundle) {
if (DEBUG) Log.d(TAG, "onHotwordEvent: " + eventType);
- if (eventType == HotwordRecognizer.EVENT_TYPE_STATE_CHANGED) {
- if (eventBundle != null && eventBundle.containsKey(HotwordRecognizer.PROMPT_TEXT)) {
- new KeyguardMessageArea.Helper(
- (View) getSecurityView(mCurrentSecuritySelection))
- .setMessage(eventBundle.getString(HotwordRecognizer.PROMPT_TEXT),true);
+ if (eventType == HotwordRecognitionService.EVENT_TYPE_PROMPT_CHANGED) {
+ if (eventBundle != null
+ && eventBundle.containsKey(HotwordRecognitionService.KEY_PROMPT_TEXT)) {
+ new KeyguardMessageArea
+ .Helper((View) getSecurityView(mCurrentSecuritySelection))
+ .setMessage(eventBundle.getString(
+ HotwordRecognitionService.KEY_PROMPT_TEXT),true);
}
}
}
diff --git a/packages/SystemUI/res/drawable-nodpi/lightning.png b/packages/SystemUI/res/drawable-nodpi/lightning.png
deleted file mode 100644
index 29de308..0000000
--- a/packages/SystemUI/res/drawable-nodpi/lightning.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
index 0812e80..b2c8aee 100644
--- a/packages/SystemUI/res/values/arrays.xml
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -51,5 +51,14 @@
<item>#FFFF3300</item>
<item>#FFFFFFFF</item>
</array>
-
+ <array name="batterymeter_bolt_points">
+ <item>88</item> <item>0</item>
+ <item>459</item><item>1</item>
+ <item>238</item><item>333</item>
+ <item>525</item><item>310</item>
+ <item>120</item><item>840</item>
+ <item>82</item> <item>818</item>
+ <item>246</item><item>373</item>
+ <item>0</item> <item>408</item>
+ </array>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index be5c326..2257617 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -23,12 +23,13 @@ import android.content.IntentFilter;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
-import android.graphics.LightingColorFilter;
import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
import android.os.BatteryManager;
import android.os.Bundle;
import android.provider.Settings;
@@ -43,26 +44,27 @@ public class BatteryMeterView extends View implements DemoMode {
public static final boolean SINGLE_DIGIT_PERCENT = false;
public static final boolean SHOW_100_PERCENT = false;
- private static final LightingColorFilter LIGHTNING_FILTER_OPAQUE =
- new LightingColorFilter(0x00000000, 0x00000000);
- private static final LightingColorFilter LIGHTNING_FILTER_TRANS =
- new LightingColorFilter(0x00999999, 0x00000000);
-
public static final int FULL = 96;
public static final int EMPTY = 4;
int[] mColors;
boolean mShowPercent = true;
- Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint;
+ Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
int mButtonHeight;
private float mTextHeight, mWarningTextHeight;
- Drawable mLightning;
private int mHeight;
private int mWidth;
private String mWarningString;
private final int mChargeColor;
+ private final float[] mBoltPoints;
+ private final Path mBoltPath = new Path();
+
+ private final RectF mFrame = new RectF();
+ private final RectF mButtonFrame = new RectF();
+ private final RectF mClipFrame = new RectF();
+ private final Rect mBoltFrame = new Rect();
private class BatteryTracker extends BroadcastReceiver {
// current battery status
@@ -175,7 +177,8 @@ public class BatteryMeterView extends View implements DemoMode {
mColors[2*i] = levels.getInt(i, 0);
mColors[2*i+1] = colors.getColor(i, 0);
}
-
+ levels.recycle();
+ colors.recycle();
mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
context.getContentResolver(), "status_bar_show_battery_percent", 0);
@@ -198,8 +201,28 @@ public class BatteryMeterView extends View implements DemoMode {
mWarningTextPaint.setTypeface(font);
mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
- mLightning = getResources().getDrawable(R.drawable.lightning);
mChargeColor = getResources().getColor(R.color.batterymeter_charge_color);
+
+ mBoltPaint = new Paint();
+ mBoltPaint.setAntiAlias(true);
+ mBoltPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); // punch hole
+ setLayerType(LAYER_TYPE_HARDWARE, null);
+ mBoltPoints = loadBoltPoints(res);
+ }
+
+ private static float[] loadBoltPoints(Resources res) {
+ final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
+ int maxX = 0, maxY = 0;
+ for (int i = 0; i < pts.length; i += 2) {
+ maxX = Math.max(maxX, pts[i]);
+ maxY = Math.max(maxY, pts[i + 1]);
+ }
+ final float[] ptsF = new float[pts.length];
+ for (int i = 0; i < pts.length; i += 2) {
+ ptsF[i] = (float)pts[i] / maxX;
+ ptsF[i + 1] = (float)pts[i + 1] / maxY;
+ }
+ return ptsF;
}
@Override
@@ -220,15 +243,6 @@ public class BatteryMeterView extends View implements DemoMode {
return color;
}
- // TODO jspurlock - remove once we draw hollow bolt in code
- public void setBarTransparent(boolean isTransparent) {
- mLightning.setColorFilter(isTransparent ? LIGHTNING_FILTER_TRANS : LIGHTNING_FILTER_OPAQUE);
- BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
- if (tracker.plugged) {
- postInvalidate();
- }
- }
-
@Override
public void draw(Canvas c) {
BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
@@ -243,22 +257,19 @@ public class BatteryMeterView extends View implements DemoMode {
mButtonHeight = (int) (height * 0.12f);
- final RectF frame = new RectF(0, 0, width, height);
- frame.offset(pl, pt);
-
- // Log.v("BatteryGauge", String.format("canvas: %dx%d frame: %s",
- // c.getWidth(), c.getHeight(), frame.toString()));
+ mFrame.set(0, 0, width, height);
+ mFrame.offset(pl, pt);
- final RectF buttonframe = new RectF(
- frame.left + width * 0.25f,
- frame.top,
- frame.right - width * 0.25f,
- frame.top + mButtonHeight);
+ mButtonFrame.set(
+ mFrame.left + width * 0.25f,
+ mFrame.top,
+ mFrame.right - width * 0.25f,
+ mFrame.top + mButtonHeight);
- frame.top += mButtonHeight;
+ mFrame.top += mButtonHeight;
// first, draw the battery shape
- c.drawRect(frame, mFramePaint);
+ c.drawRect(mFrame, mFramePaint);
// fill 'er up
final int pct = tracker.level;
@@ -271,15 +282,14 @@ public class BatteryMeterView extends View implements DemoMode {
drawFrac = 0f;
}
- c.drawRect(buttonframe,
- drawFrac == 1f ? mBatteryPaint : mFramePaint);
+ c.drawRect(mButtonFrame, drawFrac == 1f ? mBatteryPaint : mFramePaint);
- RectF clip = new RectF(frame);
- clip.top += (frame.height() * (1f - drawFrac));
+ mClipFrame.set(mFrame);
+ mClipFrame.top += (mFrame.height() * (1f - drawFrac));
c.save(Canvas.CLIP_SAVE_FLAG);
- c.clipRect(clip);
- c.drawRect(frame, mBatteryPaint);
+ c.clipRect(mClipFrame);
+ c.drawRect(mFrame, mBatteryPaint);
c.restore();
if (level <= EMPTY) {
@@ -287,11 +297,28 @@ public class BatteryMeterView extends View implements DemoMode {
final float y = (mHeight + mWarningTextHeight) * 0.48f;
c.drawText(mWarningString, x, y, mWarningTextPaint);
} else if (tracker.plugged) {
- final Rect r = new Rect(
- (int)frame.left + width / 4, (int)frame.top + height / 5,
- (int)frame.right - width / 4, (int)frame.bottom - height / 6);
- mLightning.setBounds(r);
- mLightning.draw(c);
+ // draw the bolt
+ final int bl = (int)(mFrame.left + width / 4f);
+ final int bt = (int)(mFrame.top + height / 6f);
+ final int br = (int)(mFrame.right - width / 5f);
+ final int bb = (int)(mFrame.bottom - height / 6f);
+ if (mBoltFrame.left != bl || mBoltFrame.top != bt
+ || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+ mBoltFrame.set(bl, bt, br, bb);
+ mBoltPath.reset();
+ mBoltPath.moveTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ for (int i = 2; i < mBoltPoints.length; i += 2) {
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+ }
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ }
+ c.drawPath(mBoltPath, mBoltPaint);
} else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
mTextPaint.setTextSize(height *
(SINGLE_DIGIT_PERCENT ? 0.75f
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index f8b6ca6..b263a6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.ActivityManager;
import android.content.Context;
@@ -28,7 +29,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
-import com.android.systemui.BatteryMeterView;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
@@ -53,9 +53,7 @@ public class PhoneStatusBarView extends PanelBar {
private final int mTransparent;
private final float mAlphaWhenOpaque;
private final float mAlphaWhenTransparent = 1;
- private View mLeftSide;
- private View mRightSide;
- private BatteryMeterView mBattery;
+ private View mLeftSide, mStatusIcons, mSignalCluster, mClock;
public StatusBarTransitions(Context context) {
super(context, PhoneStatusBarView.this);
@@ -66,8 +64,9 @@ public class PhoneStatusBarView extends PanelBar {
public void init() {
mLeftSide = findViewById(R.id.notification_icon_area);
- mRightSide = findViewById(R.id.system_icon_area);
- mBattery = (BatteryMeterView) findViewById(R.id.battery);
+ mStatusIcons = findViewById(R.id.statusIcons);
+ mSignalCluster = findViewById(R.id.signal_battery_cluster);
+ mClock = findViewById(R.id.clock);
applyMode(getMode(), false /*animate*/);
}
@@ -96,17 +95,22 @@ public class PhoneStatusBarView extends PanelBar {
}
private void applyMode(int mode, boolean animate) {
- if (mLeftSide == null || mRightSide == null) return;
- mBattery.setBarTransparent(isTransparent(mode));
+ if (mLeftSide == null) return; // pre-init
float newAlpha = getAlphaFor(mode);
if (animate) {
- ObjectAnimator lhs = animateTransitionTo(mLeftSide, newAlpha);
- lhs.start();
- // TODO jspurlock - fix conflicting rhs animations on tablets
- mRightSide.setAlpha(newAlpha);
+ AnimatorSet anims = new AnimatorSet();
+ anims.playTogether(
+ animateTransitionTo(mLeftSide, newAlpha),
+ animateTransitionTo(mStatusIcons, newAlpha),
+ animateTransitionTo(mSignalCluster, newAlpha),
+ animateTransitionTo(mClock, newAlpha)
+ );
+ anims.start();
} else {
mLeftSide.setAlpha(newAlpha);
- mRightSide.setAlpha(newAlpha);
+ mStatusIcons.setAlpha(newAlpha);
+ mSignalCluster.setAlpha(newAlpha);
+ mClock.setAlpha(newAlpha);
}
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 75cf5d0..1e3fb40 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1574,12 +1574,12 @@ public final class ActivityManagerService extends ActivityManagerNative
mSystemThread.installSystemApplicationInfo(info);
synchronized (mSelf) {
- ProcessRecord app = mSelf.newProcessRecordLocked(
- mSystemThread.getApplicationThread(), info,
+ ProcessRecord app = mSelf.newProcessRecordLocked(info,
info.processName, false);
app.persistent = true;
app.pid = MY_PID;
app.maxAdj = ProcessList.SYSTEM_ADJ;
+ app.makeActive(mSystemThread.getApplicationThread(), mSelf.mProcessStats);
mSelf.mProcessNames.put(app.processName, app.uid, app);
synchronized (mSelf.mPidsSelfLocked) {
mSelf.mPidsSelfLocked.put(app.pid, app);
@@ -2282,7 +2282,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (app == null) {
- app = newProcessRecordLocked(null, info, processName, isolated);
+ app = newProcessRecordLocked(info, processName, isolated);
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
@@ -3628,6 +3628,7 @@ public final class ActivityManagerService extends ActivityManagerNative
info.append(" (").append(activity.shortComponentName).append(")");
}
info.append("\n");
+ info.append("PID: ").append(app.pid).append("\n");
if (annotation != null) {
info.append("Reason: ").append(annotation).append("\n");
}
@@ -4487,7 +4488,7 @@ public final class ActivityManagerService extends ActivityManagerNative
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
- app.thread = thread;
+ app.makeActive(thread, mProcessStats);
app.curAdj = app.setAdj = -100;
app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.forcingToForeground = null;
@@ -7544,8 +7545,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// GLOBAL MANAGEMENT
// =========================================================
- final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
- ApplicationInfo info, String customProcess, boolean isolated) {
+ final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
+ boolean isolated) {
String proc = customProcess != null ? customProcess : info.processName;
BatteryStatsImpl.Uid.Proc ps = null;
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
@@ -7573,8 +7574,7 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (stats) {
ps = stats.getProcessStatsLocked(info.uid, proc);
}
- return new ProcessRecord(ps, thread, info, proc, uid,
- mProcessStats.getProcessStateLocked(info.packageName, info.uid, proc));
+ return new ProcessRecord(ps, info, proc, uid);
}
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) {
@@ -7586,7 +7586,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (app == null) {
- app = newProcessRecordLocked(null, info, null, isolated);
+ app = newProcessRecordLocked(info, null, isolated);
mProcessNames.put(info.processName, app.uid, app);
if (isolated) {
mIsolatedProcesses.put(app.uid, app);
@@ -11788,7 +11788,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
- app.thread = null;
+ app.makeInactive(mProcessStats);
app.forcingToForeground = null;
app.foregroundServices = false;
app.foregroundActivities = false;
@@ -14692,7 +14692,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private final void setProcessTrackerState(ProcessRecord proc, int memFactor, long now) {
- proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
+ if (proc.thread != null) {
+ proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
+ }
}
private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 8d27c5c..2b76e71 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1110,8 +1110,10 @@ final class ActivityStack {
case PAUSED:
// This case created for transitioning activities from
// translucent to opaque {@link Activity#convertToOpaque}.
- mStackSupervisor.mStoppingActivities.remove(r);
- stopActivityLocked(r);
+ if (!mStackSupervisor.mStoppingActivities.contains(r)) {
+ mStackSupervisor.mStoppingActivities.add(r);
+ }
+ mStackSupervisor.scheduleIdleLocked();
break;
default:
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index f1a030e..283d122 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -52,13 +52,13 @@ final class ProcessRecord {
final int uid; // uid of process; may be different from 'info' if isolated
final int userId; // user of process.
final String processName; // name of the process
- final ProcessStats.ProcessState baseProcessTracker;
// List of packages running in the process
final ArrayMap<String, ProcessStats.ProcessState> pkgList
= new ArrayMap<String, ProcessStats.ProcessState>();
IApplicationThread thread; // the actual proc... may be null only if
// 'persistent' is true (in which case we
// are in the process of launching the app)
+ ProcessStats.ProcessState baseProcessTracker;
int pid; // The process of this application; 0 if none
boolean starting; // True if the process is being started
long lastActivityTime; // For managing the LRU list
@@ -349,18 +349,15 @@ final class ProcessRecord {
}
}
- ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread,
- ApplicationInfo _info, String _processName, int _uid,
- ProcessStats.ProcessState tracker) {
+ ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, ApplicationInfo _info,
+ String _processName, int _uid) {
batteryStats = _batteryStats;
info = _info;
isolated = _info.uid != _uid;
uid = _uid;
userId = UserHandle.getUserId(_uid);
processName = _processName;
- baseProcessTracker = tracker;
- pkgList.put(_info.packageName, tracker);
- thread = _thread;
+ pkgList.put(_info.packageName, null);
maxAdj = ProcessList.UNKNOWN_ADJ;
curRawAdj = setRawAdj = -100;
curAdj = setAdj = -100;
@@ -374,7 +371,53 @@ final class ProcessRecord {
shortStringName = null;
stringName = null;
}
-
+
+ public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
+ if (thread == null) {
+ final ProcessStats.ProcessState origBase = baseProcessTracker;
+ if (origBase != null) {
+ origBase.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
+ origBase.makeInactive();
+ }
+ baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
+ processName);
+ baseProcessTracker.makeActive();
+ for (int i=0; i<pkgList.size(); i++) {
+ ProcessStats.ProcessState ps = pkgList.valueAt(i);
+ if (ps != null && ps != origBase) {
+ ps.makeInactive();
+ }
+ ps = tracker.getProcessStateLocked(pkgList.keyAt(i), info.uid, processName);
+ if (ps != baseProcessTracker) {
+ ps.makeActive();
+ }
+ pkgList.setValueAt(i, ps);
+ }
+ }
+ thread = _thread;
+ }
+
+ public void makeInactive(ProcessStatsService tracker) {
+ if (thread != null) {
+ thread = null;
+ final ProcessStats.ProcessState origBase = baseProcessTracker;
+ if (origBase != null) {
+ origBase.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
+ origBase.makeInactive();
+ }
+ baseProcessTracker = null;
+ for (int i=0; i<pkgList.size(); i++) {
+ ProcessStats.ProcessState ps = pkgList.valueAt(i);
+ if (ps != null && ps != origBase) {
+ ps.makeInactive();
+ }
+ pkgList.setValueAt(i, null);
+ }
+ }
+ }
+
/**
* This method returns true if any of the activities within the process record are interesting
* to the user. See HistoryRecord.isInterestingToUserLocked()
@@ -518,10 +561,22 @@ final class ProcessRecord {
long now = SystemClock.uptimeMillis();
baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
tracker.getMemFactorLocked(), now, pkgList);
- if (pkgList.size() != 1) {
+ final int N = pkgList.size();
+ if (N != 1) {
+ for (int i=0; i<N; i++) {
+ ProcessStats.ProcessState ps = pkgList.valueAt(i);
+ if (ps != null && ps != baseProcessTracker) {
+ ps.makeInactive();
+ }
+
+ }
pkgList.clear();
- pkgList.put(info.packageName, tracker.getProcessStateLocked(
- info.packageName, info.uid, processName));
+ ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
+ info.packageName, info.uid, processName);
+ pkgList.put(info.packageName, ps);
+ if (thread != null && ps != baseProcessTracker) {
+ ps.makeActive();
+ }
}
}
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index 43ae46f..c180f6e 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -54,12 +54,12 @@ public final class ProcessStatsService extends IProcessStats.Stub {
// exists in and the offset into the array to find it. The constants below
// define the encoding of that data in an integer.
- static final int MAX_HISTORIC_STATES = 4; // Maximum number of historic states we will keep.
+ static final int MAX_HISTORIC_STATES = 6; // Maximum number of historic states we will keep.
static final String STATE_FILE_PREFIX = "state-"; // Prefix to use for state filenames.
static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames.
static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in.
static long WRITE_PERIOD = 30*60*1000; // Write file every 30 minutes or so.
- static long COMMIT_PERIOD = 24*60*60*1000; // Commit current stats every day.
+ static long COMMIT_PERIOD = 12*60*60*1000; // Commit current stats every 12 hours.
final ActivityManagerService mAm;
final File mBaseDir;
@@ -132,7 +132,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
ArrayMap<String, ProcessStats.ServiceState> services = pkg.mServices;
for (int k=0; k<services.size(); k++) {
ProcessStats.ServiceState service = services.valueAt(k);
- if (service.isActive()) {
+ if (service.isInUse()) {
if (service.mStartedState != ProcessStats.STATE_NOTHING) {
service.setStarted(true, memFactor, now);
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 39756c3..8293bb8 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -318,6 +318,7 @@ final class ServiceRecord extends Binder {
if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
tracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
serviceInfo.applicationInfo.uid, serviceInfo.processName, serviceInfo.name);
+ tracker.makeActive();
}
return tracker;
}
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
index 2563b58..926f822 100644
--- a/services/java/com/android/server/print/PrintManagerService.java
+++ b/services/java/com/android/server/print/PrintManagerService.java
@@ -41,6 +41,8 @@ import android.util.SparseArray;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -298,6 +300,27 @@ public final class PrintManagerService extends IPrintManager.Stub {
}
}
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump PrintManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (mLock) {
+ pw.println("PRINT MANAGER STATE (dumpsys print)");
+ final int userStateCount = mUserStates.size();
+ for (int i = 0; i < userStateCount; i++) {
+ UserState userState = mUserStates.get(i);
+ userState.dump(fd, pw, "");
+ pw.println();
+ }
+ }
+ }
+
private void registerContentObservers() {
final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
Settings.Secure.ENABLED_PRINT_SERVICES);
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
index 2ded202..ddff0ae 100644
--- a/services/java/com/android/server/print/RemotePrintService.java
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -41,6 +41,7 @@ import android.util.Slog;
import com.android.internal.R;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -137,6 +138,19 @@ final class RemotePrintService implements DeathRecipient {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
+ public void dump(PrintWriter pw, String prefix) {
+ String tab = " ";
+ pw.append(prefix).append("service:").println();
+ pw.append(prefix).append(tab).append("componentName=")
+ .append(mComponentName.flattenToString()).println();
+ pw.append(prefix).append(tab).append("destroyed=")
+ .append(String.valueOf(mDestroyed)).println();
+ pw.append(prefix).append(tab).append("bound=")
+ .append(String.valueOf(isBound())).println();
+ pw.append(prefix).append(tab).append("hasDicoverySession=")
+ .append(String.valueOf(mHasPrinterDiscoverySession));
+ }
+
private void failAllActivePrintJobs() {
List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(mComponentName,
PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY);
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
index db0eb33..28a6186 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -34,11 +34,14 @@ import android.print.IPrintSpoolerCallbacks;
import android.print.IPrintSpoolerClient;
import android.print.PrintAttributes;
import android.print.PrintJobInfo;
+import android.print.PrintManager;
import android.util.Slog;
import android.util.TimedRemoteCaller;
import libcore.io.IoUtils;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.TimeoutException;
@@ -291,6 +294,28 @@ final class RemotePrintSpooler {
}
}
+ public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
+ synchronized (mLock) {
+ pw.append(prefix).append("destroyed=")
+ .append(String.valueOf(mDestroyed)).println();
+ pw.append(prefix).append("bound=")
+ .append((mRemoteInstance != null) ? "true" : "false").println();
+ pw.append(prefix).append("print jobs:").println();
+ if (mRemoteInstance != null) {
+ List<PrintJobInfo> printJobs = getPrintJobInfos(null,
+ PrintJobInfo.STATE_ANY, PrintManager.APP_ID_ANY);
+ if (printJobs != null) {
+ final int printJobCount = printJobs.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo printJob = printJobs.get(i);
+ pw.append(prefix).append(prefix).append(printJob.toString());
+ pw.println();
+ }
+ }
+ }
+ }
+ }
+
private void onAllPrintJobsHandled() {
synchronized (mLock) {
throwIfDestroyedLocked();
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
index b37a0d9..5392975 100644
--- a/services/java/com/android/server/print/UserState.java
+++ b/services/java/com/android/server/print/UserState.java
@@ -39,14 +39,16 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import com.android.internal.os.SomeArgs;
import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -72,14 +74,14 @@ final class UserState implements PrintSpoolerCallbacks {
private final Intent mQueryIntent =
new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
- private final Map<ComponentName, RemotePrintService> mActiveServices =
- new HashMap<ComponentName, RemotePrintService>();
+ private final ArrayMap<ComponentName, RemotePrintService> mActiveServices =
+ new ArrayMap<ComponentName, RemotePrintService>();
private final List<PrintServiceInfo> mInstalledServices =
new ArrayList<PrintServiceInfo>();
private final Set<ComponentName> mEnabledServices =
- new HashSet<ComponentName>();
+ new ArraySet<ComponentName>();
private final Object mLock;
@@ -318,6 +320,57 @@ final class UserState implements PrintSpoolerCallbacks {
mDestroyed = true;
}
+ public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
+ pw.append(prefix).append("user state ").append(String.valueOf(mUserId)).append(":");
+ pw.println();
+
+ String tab = " ";
+
+ pw.append(prefix).append(tab).append("installed services:").println();
+ final int installedServiceCount = mInstalledServices.size();
+ for (int i = 0; i < installedServiceCount; i++) {
+ PrintServiceInfo installedService = mInstalledServices.get(i);
+ String installedServicePrefix = prefix + tab + tab;
+ pw.append(installedServicePrefix).append("service:").println();
+ ResolveInfo resolveInfo = installedService.getResolveInfo();
+ ComponentName componentName = new ComponentName(
+ resolveInfo.serviceInfo.packageName,
+ resolveInfo.serviceInfo.name);
+ pw.append(installedServicePrefix).append(tab).append("componentName=")
+ .append(componentName.flattenToString()).println();
+ pw.append(installedServicePrefix).append(tab).append("settingsActivity=")
+ .append(installedService.getSettingsActivityName()).println();
+ pw.append(installedServicePrefix).append(tab).append("addPrintersActivity=")
+ .append(installedService.getAddPrintersActivityName()).println();
+ }
+
+ pw.append(prefix).append(tab).append("enabled services:").println();
+ for (ComponentName enabledService : mEnabledServices) {
+ String enabledServicePrefix = prefix + tab + tab;
+ pw.append(enabledServicePrefix).append("service:").println();
+ pw.append(enabledServicePrefix).append(tab).append("componentName=")
+ .append(enabledService.flattenToString());
+ pw.println();
+ }
+
+ pw.append(prefix).append(tab).append("active services:").println();
+ final int activeServiceCount = mActiveServices.size();
+ for (int i = 0; i < activeServiceCount; i++) {
+ RemotePrintService activeService = mActiveServices.valueAt(i);
+ activeService.dump(pw, prefix + tab + tab);
+ pw.println();
+ }
+
+ pw.append(prefix).append(tab).append("discovery mediator:").println();
+ if (mPrinterDiscoverySession != null) {
+ mPrinterDiscoverySession.dump(pw, prefix + tab + tab);
+ }
+
+ pw.append(prefix).append(tab).append("print spooler:").println();
+ mSpooler.dump(fd, pw, prefix + tab + tab);
+ pw.println();
+ }
+
private boolean readConfigurationLocked() {
boolean somethingChanged = false;
somethingChanged |= readInstalledPrintServicesLocked();
@@ -814,6 +867,47 @@ final class UserState implements PrintSpoolerCallbacks {
}
}
+ public void dump(PrintWriter pw, String prefix) {
+ pw.append(prefix).append("destroyed=")
+ .append(String.valueOf(mDestroyed)).println();
+
+ pw.append(prefix).append("printDiscoveryInProgress=")
+ .append(String.valueOf(!mStartedPrinterDiscoveryTokens.isEmpty())).println();
+
+ String tab = " ";
+
+ pw.append(prefix).append(tab).append("printer discovery observers:").println();
+ final int observerCount = mDiscoveryObservers.beginBroadcast();
+ for (int i = 0; i < observerCount; i++) {
+ IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
+ pw.append(prefix).append(prefix).append(observer.toString());
+ pw.println();
+ }
+ mDiscoveryObservers.finishBroadcast();
+
+ pw.append(prefix).append(tab).append("start discovery requests:").println();
+ final int tokenCount = this.mStartedPrinterDiscoveryTokens.size();
+ for (int i = 0; i < tokenCount; i++) {
+ IBinder token = mStartedPrinterDiscoveryTokens.get(i);
+ pw.append(prefix).append(tab).append(tab).append(token.toString()).println();
+ }
+
+ pw.append(prefix).append(tab).append("tracked printer requests:").println();
+ final int trackedPrinters = mStateTrackedPrinters.size();
+ for (int i = 0; i < trackedPrinters; i++) {
+ PrinterId printer = mStateTrackedPrinters.get(i);
+ pw.append(prefix).append(tab).append(tab).append(printer.toString()).println();
+ }
+
+ pw.append(prefix).append(tab).append("printers:").println();
+ final int pritnerCount = mPrinters.size();
+ for (int i = 0; i < pritnerCount; i++) {
+ PrinterInfo printer = mPrinters.valueAt(i);
+ pw.append(prefix).append(tab).append(tab).append(
+ printer.toString()).println();
+ }
+ }
+
private void handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters) {
final int observerCount = mDiscoveryObservers.beginBroadcast();
for (int i = 0; i < observerCount; i++) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
index 5256b58..04ce9d0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -24,10 +24,13 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.content.res.BridgeResources.NinePatchInputStream;
import android.graphics.BitmapFactory.Options;
+import android.graphics.Bitmap_Delegate.BitmapCreateFlags;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
+import java.util.EnumSet;
+import java.util.Set;
/**
* Delegate implementing the native methods of android.graphics.BitmapFactory
@@ -98,8 +101,12 @@ import java.io.InputStream;
//TODO support rescaling
Density density = Density.MEDIUM;
+ Set<BitmapCreateFlags> bitmapCreateFlags = EnumSet.of(BitmapCreateFlags.MUTABLE);
if (opts != null) {
density = Density.getEnum(opts.inDensity);
+ if (opts.inPremultiplied) {
+ bitmapCreateFlags.add(BitmapCreateFlags.PREMULTIPLIED);
+ }
}
try {
@@ -112,7 +119,7 @@ import java.io.InputStream;
npis, true /*is9Patch*/, false /*convert*/);
// get the bitmap and chunk objects.
- bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), true /*isMutable*/,
+ bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), bitmapCreateFlags,
density);
NinePatchChunk chunk = ninePatch.getChunk();
@@ -127,7 +134,7 @@ import java.io.InputStream;
padding.bottom = paddingarray[3];
} else {
// load the bitmap directly.
- bm = Bitmap_Delegate.createBitmap(is, true, density);
+ bm = Bitmap_Delegate.createBitmap(is, bitmapCreateFlags, density);
}
} catch (IOException e) {
Bridge.getLog().error(null,"Failed to load image" , e, null);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 4121f79..ec284ac 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -33,6 +33,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.Buffer;
import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Set;
import javax.imageio.ImageIO;
@@ -51,6 +53,10 @@ import javax.imageio.ImageIO;
*/
public final class Bitmap_Delegate {
+ public enum BitmapCreateFlags {
+ PREMULTIPLIED, MUTABLE
+ }
+
// ---- delegate manager ----
private static final DelegateManager<Bitmap_Delegate> sManager =
new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
@@ -93,10 +99,25 @@ public final class Bitmap_Delegate {
*/
public static Bitmap createBitmap(File input, boolean isMutable, Density density)
throws IOException {
+ return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density);
+ }
+
+ /**
+ * Creates and returns a {@link Bitmap} initialized with the given file content.
+ *
+ * @param input the file from which to read the bitmap content
+ * @param density the density associated with the bitmap
+ *
+ * @see Bitmap#isPremultiplied()
+ * @see Bitmap#isMutable()
+ * @see Bitmap#getDensity()
+ */
+ public static Bitmap createBitmap(File input, Set<BitmapCreateFlags> createFlags,
+ Density density) throws IOException {
// create a delegate with the content of the file.
Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
- return createBitmap(delegate, isMutable, density.getDpiValue());
+ return createBitmap(delegate, createFlags, density.getDpiValue());
}
/**
@@ -111,10 +132,26 @@ public final class Bitmap_Delegate {
*/
public static Bitmap createBitmap(InputStream input, boolean isMutable, Density density)
throws IOException {
+ return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density);
+ }
+
+ /**
+ * Creates and returns a {@link Bitmap} initialized with the given stream content.
+ *
+ * @param input the stream from which to read the bitmap content
+ * @param createFlags
+ * @param density the density associated with the bitmap
+ *
+ * @see Bitmap#isPremultiplied()
+ * @see Bitmap#isMutable()
+ * @see Bitmap#getDensity()
+ */
+ public static Bitmap createBitmap(InputStream input, Set<BitmapCreateFlags> createFlags,
+ Density density) throws IOException {
// create a delegate with the content of the stream.
Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
- return createBitmap(delegate, isMutable, density.getDpiValue());
+ return createBitmap(delegate, createFlags, density.getDpiValue());
}
/**
@@ -129,10 +166,26 @@ public final class Bitmap_Delegate {
*/
public static Bitmap createBitmap(BufferedImage image, boolean isMutable,
Density density) throws IOException {
+ return createBitmap(image, getPremultipliedBitmapCreateFlags(isMutable), density);
+ }
+
+ /**
+ * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
+ *
+ * @param image the bitmap content
+ * @param createFlags
+ * @param density the density associated with the bitmap
+ *
+ * @see Bitmap#isPremultiplied()
+ * @see Bitmap#isMutable()
+ * @see Bitmap#getDensity()
+ */
+ public static Bitmap createBitmap(BufferedImage image, Set<BitmapCreateFlags> createFlags,
+ Density density) throws IOException {
// create a delegate with the given image.
Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
- return createBitmap(delegate, isMutable, density.getDpiValue());
+ return createBitmap(delegate, createFlags, density.getDpiValue());
}
/**
@@ -203,7 +256,7 @@ public final class Bitmap_Delegate {
@LayoutlibDelegate
/*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
- int height, int nativeConfig, boolean mutable) {
+ int height, int nativeConfig, boolean isMutable) {
int imageType = getBufferedImageType(nativeConfig);
// create the image
@@ -216,7 +269,8 @@ public final class Bitmap_Delegate {
// create a delegate with the content of the stream.
Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig));
- return createBitmap(delegate, mutable, Bitmap.getDefaultDensity());
+ return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable),
+ Bitmap.getDefaultDensity());
}
@LayoutlibDelegate
@@ -244,7 +298,8 @@ public final class Bitmap_Delegate {
// create a delegate with the content of the stream.
Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig));
- return createBitmap(delegate, isMutable, Bitmap.getDefaultDensity());
+ return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable),
+ Bitmap.getDefaultDensity());
}
@LayoutlibDelegate
@@ -464,7 +519,7 @@ public final class Bitmap_Delegate {
Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ALPHA_8);
// the density doesn't matter, it's set by the Java method.
- return createBitmap(delegate, false /*isMutable*/,
+ return createBitmap(delegate, EnumSet.of(BitmapCreateFlags.MUTABLE),
Density.DEFAULT_DENSITY /*density*/);
}
@@ -546,15 +601,27 @@ public final class Bitmap_Delegate {
mConfig = config;
}
- private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) {
+ private static Bitmap createBitmap(Bitmap_Delegate delegate,
+ Set<BitmapCreateFlags> createFlags, int density) {
// get its native_int
int nativeInt = sManager.addNewDelegate(delegate);
+ int width = delegate.mImage.getWidth();
+ int height = delegate.mImage.getHeight();
+ boolean isMutable = createFlags.contains(BitmapCreateFlags.MUTABLE);
+ boolean isPremultiplied = createFlags.contains(BitmapCreateFlags.PREMULTIPLIED);
+
// and create/return a new Bitmap with it
- // TODO: pass correct width, height, isPremultiplied
- return new Bitmap(nativeInt, null /* buffer */, -1 /* width */, -1 /* height */, density,
- isMutable, true /* isPremultiplied */,
- null /*ninePatchChunk*/, null /* layoutBounds */);
+ return new Bitmap(nativeInt, null /* buffer */, width, height, density, isMutable,
+ isPremultiplied, null /*ninePatchChunk*/, null /* layoutBounds */);
+ }
+
+ private static Set<BitmapCreateFlags> getPremultipliedBitmapCreateFlags(boolean isMutable) {
+ Set<BitmapCreateFlags> createFlags = EnumSet.of(BitmapCreateFlags.PREMULTIPLIED);
+ if (isMutable) {
+ createFlags.add(BitmapCreateFlags.MUTABLE);
+ }
+ return createFlags;
}
/**