Merge "Update API for launcher apps to use abstract class."
diff --git a/Android.mk b/Android.mk
index 3a3756b..216d8a2d4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -94,8 +94,6 @@
core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
core/java/android/app/backup/IRestoreObserver.aidl \
core/java/android/app/backup/IRestoreSession.aidl \
- core/java/android/app/maintenance/IIdleCallback.aidl \
- core/java/android/app/maintenance/IIdleService.aidl \
core/java/android/bluetooth/IBluetooth.aidl \
core/java/android/bluetooth/IBluetoothA2dp.aidl \
core/java/android/bluetooth/IBluetoothA2dpSink.aidl \
@@ -610,8 +608,12 @@
framework_docs_LOCAL_DROIDDOC_HTML_DIR := docs/html
# The since flag (-since N.xml API_LEVEL) is used to add API Level information
# to the reference documentation. Must be in order of oldest to newest.
+#
+# Conscrypt (com.android.org.conscrypt) is an implementation detail and should
+# not be referenced in the documentation.
framework_docs_LOCAL_DROIDDOC_OPTIONS := \
-knowntags ./frameworks/base/docs/knowntags.txt \
+ -hidePackage com.android.org.conscrypt \
-since $(SRC_API_DIR)/1.xml 1 \
-since $(SRC_API_DIR)/2.xml 2 \
-since $(SRC_API_DIR)/3.xml 3 \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 5d92792..1968a78 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -34,9 +34,9 @@
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
@@ -194,10 +194,15 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/wearable)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/ITv*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/task)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app/task)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/TaskManager)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/maintenance)
+
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/api/current.txt b/api/current.txt
index 8ddde2b..cd58b21 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -91,6 +91,7 @@
field public static final java.lang.String NFC = "android.permission.NFC";
field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
+ field public static final java.lang.String READ_ALL_VOICEMAIL = "com.android.voicemail.permission.READ_ALL_VOICEMAIL";
field public static final java.lang.String READ_CALENDAR = "android.permission.READ_CALENDAR";
field public static final java.lang.String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
field public static final java.lang.String READ_CONTACTS = "android.permission.READ_CONTACTS";
@@ -320,6 +321,8 @@
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
field public static final int backgroundSplit = 16843659; // 0x101038b
field public static final int backgroundStacked = 16843658; // 0x101038a
+ field public static final int backgroundTint = 16843885; // 0x101046d
+ field public static final int backgroundTintMode = 16843886; // 0x101046e
field public static final int backupAgent = 16843391; // 0x101027f
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
@@ -344,6 +347,8 @@
field public static final int buttonStyleInset = 16842826; // 0x101004a
field public static final int buttonStyleSmall = 16842825; // 0x1010049
field public static final int buttonStyleToggle = 16842827; // 0x101004b
+ field public static final int buttonTint = 16843889; // 0x1010471
+ field public static final int buttonTintMode = 16843890; // 0x1010472
field public static final int cacheColorHint = 16843009; // 0x1010101
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
@@ -554,6 +559,8 @@
field public static final int footerDividersEnabled = 16843311; // 0x101022f
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
+ field public static final int foregroundTint = 16843887; // 0x101046f
+ field public static final int foregroundTintMode = 16843888; // 0x1010470
field public static final int format = 16843013; // 0x1010105
field public static final int format12Hour = 16843722; // 0x10103ca
field public static final int format24Hour = 16843723; // 0x10103cb
@@ -636,6 +643,8 @@
field public static final int indeterminateDuration = 16843069; // 0x101013d
field public static final int indeterminateOnly = 16843066; // 0x101013a
field public static final int indeterminateProgressStyle = 16843544; // 0x1010318
+ field public static final int indeterminateTint = 16843883; // 0x101046b
+ field public static final int indeterminateTintMode = 16843884; // 0x101046c
field public static final int indicatorEnd = 16843730; // 0x10103d2
field public static final int indicatorLeft = 16843021; // 0x101010d
field public static final int indicatorRight = 16843022; // 0x101010e
@@ -885,7 +894,7 @@
field public static final int permissionFlags = 16843719; // 0x10103c7
field public static final int permissionGroup = 16842762; // 0x101000a
field public static final int permissionGroupFlags = 16843717; // 0x10103c5
- field public static final int persistable = 16843823; // 0x101042f
+ field public static final int persistableMode = 16843823; // 0x101042f
field public static final int persistent = 16842765; // 0x101000d
field public static final int persistentDrawingCache = 16842990; // 0x10100ee
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
@@ -911,6 +920,8 @@
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
field public static final int progress = 16843063; // 0x1010137
+ field public static final int progressBackgroundTint = 16843879; // 0x1010467
+ field public static final int progressBackgroundTintMode = 16843880; // 0x1010468
field public static final int progressBarPadding = 16843545; // 0x1010319
field public static final int progressBarStyle = 16842871; // 0x1010077
field public static final int progressBarStyleHorizontal = 16842872; // 0x1010078
@@ -921,6 +932,8 @@
field public static final int progressBarStyleSmallInverse = 16843400; // 0x1010288
field public static final int progressBarStyleSmallTitle = 16843279; // 0x101020f
field public static final int progressDrawable = 16843068; // 0x101013c
+ field public static final int progressTint = 16843877; // 0x1010465
+ field public static final int progressTintMode = 16843878; // 0x1010466
field public static final int prompt = 16843131; // 0x101017b
field public static final int propertyName = 16843489; // 0x10102e1
field public static final int protectionLevel = 16842761; // 0x1010009
@@ -1013,6 +1026,8 @@
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int secondaryProgress = 16843064; // 0x1010138
+ field public static final int secondaryProgressTint = 16843881; // 0x1010469
+ field public static final int secondaryProgressTintMode = 16843882; // 0x101046a
field public static final int seekBarStyle = 16842875; // 0x101007b
field public static final int segmentedButtonStyle = 16843568; // 0x1010330
field public static final int selectAllOnFocus = 16843102; // 0x101015e
@@ -1216,6 +1231,8 @@
field public static final int thumb = 16843074; // 0x1010142
field public static final int thumbOffset = 16843075; // 0x1010143
field public static final int thumbTextPadding = 16843634; // 0x1010372
+ field public static final int thumbTint = 16843891; // 0x1010473
+ field public static final int thumbTintMode = 16843892; // 0x1010474
field public static final int thumbnail = 16843429; // 0x10102a5
field public static final int tileMode = 16843265; // 0x1010201
field public static final int timeZone = 16843724; // 0x10103cc
@@ -4203,6 +4220,9 @@
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+ method public abstract android.app.FragmentTransaction setCustomTransition(int, int);
+ method public abstract android.app.FragmentTransaction setSharedElement(android.view.View, java.lang.String);
+ method public abstract android.app.FragmentTransaction setSharedElements(android.util.Pair<android.view.View, java.lang.String>...);
method public abstract android.app.FragmentTransaction setTransition(int);
method public abstract android.app.FragmentTransaction setTransitionStyle(int);
method public abstract android.app.FragmentTransaction show(android.app.Fragment);
@@ -5229,7 +5249,7 @@
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationBlocked(android.content.ComponentName, java.lang.String);
method public boolean isDeviceOwnerApp(java.lang.String);
- method public boolean isLockTaskPermitted(android.content.ComponentName);
+ method public boolean isLockTaskPermitted(java.lang.String);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isProfileOwnerApp(java.lang.String);
method public void lockNow();
@@ -5243,7 +5263,7 @@
method public void setCameraDisabled(android.content.ComponentName, boolean);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
- method public void setLockTaskComponents(android.content.ComponentName[]) throws java.lang.SecurityException;
+ method public void setLockTaskPackages(java.lang.String[]) throws java.lang.SecurityException;
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -8042,6 +8062,7 @@
field public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1; // 0x1
field public static final int DOCUMENT_LAUNCH_NEVER = 3; // 0x3
field public static final int DOCUMENT_LAUNCH_NONE = 0; // 0x0
+ field public static final int DO_NOT_PERSIST = 1; // 0x1
field public static final int FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
@@ -8053,13 +8074,14 @@
field public static final int FLAG_IMMERSIVE = 2048; // 0x800
field public static final int FLAG_MULTIPROCESS = 1; // 0x1
field public static final int FLAG_NO_HISTORY = 128; // 0x80
- field public static final int FLAG_PERSISTABLE = 4096; // 0x1000
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
field public static final int LAUNCH_MULTIPLE = 0; // 0x0
field public static final int LAUNCH_SINGLE_INSTANCE = 3; // 0x3
field public static final int LAUNCH_SINGLE_TASK = 2; // 0x2
field public static final int LAUNCH_SINGLE_TOP = 1; // 0x1
+ field public static final int PERSIST_ACROSS_REBOOTS = 2; // 0x2
+ field public static final int PERSIST_ROOT_ONLY = 0; // 0x0
field public static final int SCREEN_ORIENTATION_BEHIND = 3; // 0x3
field public static final int SCREEN_ORIENTATION_FULL_SENSOR = 10; // 0xa
field public static final int SCREEN_ORIENTATION_FULL_USER = 13; // 0xd
@@ -8084,6 +8106,7 @@
field public int maxRecents;
field public java.lang.String parentActivityName;
field public java.lang.String permission;
+ field public int persistableMode;
field public int screenOrientation;
field public int softInputMode;
field public java.lang.String targetActivity;
@@ -8141,6 +8164,8 @@
field public int requiresSmallestWidthDp;
field public java.lang.String[] sharedLibraryFiles;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitPublicSourceDirs;
+ field public java.lang.String[] splitSourceDirs;
field public int targetSdkVersion;
field public java.lang.String taskAffinity;
field public int theme;
@@ -8209,6 +8234,8 @@
field public boolean handleProfiling;
field public java.lang.String publicSourceDir;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitPublicSourceDirs;
+ field public java.lang.String[] splitSourceDirs;
field public java.lang.String targetPackage;
}
@@ -10219,6 +10246,7 @@
method public void concat(android.graphics.Matrix);
method public void drawARGB(int, int, int, int);
method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
+ method public void drawArc(float, float, float, float, float, float, boolean, android.graphics.Paint);
method public void drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint);
method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint);
method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
@@ -10233,6 +10261,7 @@
method public void drawLines(float[], int, int, android.graphics.Paint);
method public void drawLines(float[], android.graphics.Paint);
method public void drawOval(android.graphics.RectF, android.graphics.Paint);
+ method public void drawOval(float, float, float, float, android.graphics.Paint);
method public void drawPaint(android.graphics.Paint);
method public void drawPath(android.graphics.Path, android.graphics.Paint);
method public void drawPicture(android.graphics.Picture);
@@ -10742,6 +10771,7 @@
ctor public Path();
ctor public Path(android.graphics.Path);
method public void addArc(android.graphics.RectF, float, float);
+ method public void addArc(float, float, float, float, float, float);
method public void addCircle(float, float, float, android.graphics.Path.Direction);
method public void addOval(android.graphics.RectF, android.graphics.Path.Direction);
method public void addOval(float, float, float, float, android.graphics.Path.Direction);
@@ -10751,9 +10781,12 @@
method public void addRect(android.graphics.RectF, android.graphics.Path.Direction);
method public void addRect(float, float, float, float, android.graphics.Path.Direction);
method public void addRoundRect(android.graphics.RectF, float, float, android.graphics.Path.Direction);
+ method public void addRoundRect(float, float, float, float, float, float, android.graphics.Path.Direction);
method public void addRoundRect(android.graphics.RectF, float[], android.graphics.Path.Direction);
+ method public void addRoundRect(float, float, float, float, float[], android.graphics.Path.Direction);
method public void arcTo(android.graphics.RectF, float, float, boolean);
method public void arcTo(android.graphics.RectF, float, float);
+ method public void arcTo(float, float, float, float, float, float, boolean);
method public void close();
method public void computeBounds(android.graphics.RectF, boolean);
method public void cubicTo(float, float, float, float, float, float);
@@ -15802,7 +15835,9 @@
method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName);
method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName, boolean);
method public static final android.net.Uri buildProgramUri(long);
+ method public static final android.net.Uri buildProgramsUriForChannel(long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri);
+ method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
field public static final java.lang.String AUTHORITY = "android.media.tv";
}
@@ -16381,6 +16416,18 @@
method public android.net.NetworkRequest.Builder removeTransportType(int);
}
+ public abstract interface PSKKeyManager {
+ method public abstract java.lang.String chooseClientKeyIdentity(java.lang.String, java.net.Socket);
+ method public abstract java.lang.String chooseClientKeyIdentity(java.lang.String, javax.net.ssl.SSLEngine);
+ method public abstract java.lang.String chooseServerKeyIdentityHint(java.net.Socket);
+ method public abstract java.lang.String chooseServerKeyIdentityHint(javax.net.ssl.SSLEngine);
+ method public abstract javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, java.net.Socket);
+ method public abstract javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, javax.net.ssl.SSLEngine);
+ field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
+ field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
+ field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
+ }
+
public class ParseException extends java.lang.RuntimeException {
field public java.lang.String response;
}
@@ -26004,29 +26051,44 @@
package android.service.fingerprint {
public class FingerprintManager {
- ctor public FingerprintManager(android.content.Context);
method public void enroll(long);
+ method public void enrollCancel();
method public boolean enrolledAndEnabled();
method public void remove(int);
method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
method public void stopListening();
+ field public static final int FINGERPRINT_ACQUIRED = 1; // 0x1
+ field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+ field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4; // 0x4
+ field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+ field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+ field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16; // 0x10
+ field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8; // 0x8
field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
- field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; // 0xfffffff6
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
- field public static final int FINGERPRINT_SCANNED = 1; // 0x1
- field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field public static final int FINGERPRINT_PROCESSED = 2; // 0x2
+ field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3; // 0x3
field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
}
public class FingerprintManagerReceiver {
ctor public FingerprintManagerReceiver();
+ method public void onAcquired(int);
method public void onEnrollResult(int, int);
method public void onError(int);
+ method public void onProcessed(int);
method public void onRemoved(int);
- method public void onScanned(int, int);
+ }
+
+ public class FingerprintUtils {
+ ctor public FingerprintUtils();
+ method public static void addFingerprintIdForUser(int, android.content.ContentResolver, int);
+ method public static int[] getFingerprintIdsForUser(android.content.ContentResolver, int);
+ method public static boolean removeFingerprintIdForUser(int, android.content.ContentResolver, int);
}
}
@@ -27676,8 +27738,17 @@
}
public class Subscription implements android.os.Parcelable {
- ctor public Subscription();
+ ctor public Subscription(android.content.ComponentName, java.lang.String, android.net.Uri, int, int, int, boolean, boolean);
method public int describeContents();
+ method public android.content.ComponentName getComponentName();
+ method public android.net.Uri getHandle();
+ method public android.graphics.drawable.Drawable getIcon(android.content.Context);
+ method public android.graphics.drawable.Drawable getIcon(android.content.Context, int);
+ method public java.lang.String getId();
+ method public java.lang.String getLabel(android.content.Context);
+ method public java.lang.String getShortDescription(android.content.Context);
+ method public boolean isEnabled();
+ method public boolean isSystemDefault();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
@@ -27696,6 +27767,7 @@
field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "package";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
}
public class TelecommManager {
@@ -28140,6 +28212,7 @@
method public java.lang.String getSimSerialNumber();
method public int getSimState();
method public java.lang.String getSubscriberId();
+ method public java.util.List<android.telecomm.Subscription> getSubscriptions();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public boolean hasIccCard();
@@ -28164,6 +28237,7 @@
field public static final java.lang.String EXTRA_STATE_IDLE;
field public static final java.lang.String EXTRA_STATE_OFFHOOK;
field public static final java.lang.String EXTRA_STATE_RINGING;
+ field public static final java.lang.String EXTRA_SUBSCRIPTION = "subscription";
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
@@ -32499,6 +32573,8 @@
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
method public android.graphics.drawable.Drawable getBackground();
+ method public android.content.res.ColorStateList getBackgroundTint();
+ method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
method public int getBaseline();
method public final int getBottom();
method protected float getBottomFadingEdgeStrength();
@@ -32776,6 +32852,8 @@
method public void setBackgroundColor(int);
method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
method public void setBackgroundResource(int);
+ method public void setBackgroundTint(android.content.res.ColorStateList);
+ method public void setBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public final void setBottom(int);
method public void setCameraDistance(float);
method public void setClickable(boolean);
@@ -35058,12 +35136,15 @@
method public java.lang.String getCookie(java.lang.String);
method public static synchronized android.webkit.CookieManager getInstance();
method public synchronized boolean hasCookies();
- method public void removeAllCookie();
- method public void removeExpiredCookie();
- method public void removeSessionCookie();
+ method public deprecated void removeAllCookie();
+ method public void removeAllCookies(android.webkit.ValueCallback<java.lang.Boolean>);
+ method public deprecated void removeExpiredCookie();
+ method public deprecated void removeSessionCookie();
+ method public void removeSessionCookies(android.webkit.ValueCallback<java.lang.Boolean>);
method public synchronized void setAcceptCookie(boolean);
method public static void setAcceptFileSchemeCookies(boolean);
method public void setCookie(java.lang.String, java.lang.String);
+ method public void setCookie(java.lang.String, java.lang.String, android.webkit.ValueCallback<java.lang.Boolean>);
}
public final class CookieSyncManager extends android.webkit.WebSyncManager {
@@ -35739,10 +35820,14 @@
method public boolean getSplitTrack();
method public android.graphics.drawable.Drawable getThumb();
method public int getThumbOffset();
+ method public android.content.res.ColorStateList getThumbTint();
+ method public android.graphics.PorterDuff.Mode getThumbTintMode();
method public void setKeyProgressIncrement(int);
method public void setSplitTrack(boolean);
method public void setThumb(android.graphics.drawable.Drawable);
method public void setThumbOffset(int);
+ method public void setThumbTint(android.content.res.ColorStateList);
+ method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
}
public abstract class AbsSpinner extends android.widget.AdapterView {
@@ -36157,9 +36242,13 @@
ctor public CompoundButton(android.content.Context, android.util.AttributeSet);
ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int);
ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int, int);
+ method public android.content.res.ColorStateList getButtonTint();
+ method public android.graphics.PorterDuff.Mode getButtonTintMode();
method public boolean isChecked();
method public void setButtonDrawable(int);
method public void setButtonDrawable(android.graphics.drawable.Drawable);
+ method public void setButtonTint(android.content.res.ColorStateList);
+ method public void setButtonTintMode(android.graphics.PorterDuff.Mode);
method public void setChecked(boolean);
method public void setOnCheckedChangeListener(android.widget.CompoundButton.OnCheckedChangeListener);
method public void toggle();
@@ -36420,10 +36509,14 @@
method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
method public android.graphics.drawable.Drawable getForeground();
method public int getForegroundGravity();
+ method public android.content.res.ColorStateList getForegroundTint();
+ method public android.graphics.PorterDuff.Mode getForegroundTintMode();
method public boolean getMeasureAllChildren();
method protected void onLayout(boolean, int, int, int, int);
method public void setForeground(android.graphics.drawable.Drawable);
method public void setForegroundGravity(int);
+ method public void setForegroundTint(android.content.res.ColorStateList);
+ method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
method public void setMeasureAllChildren(boolean);
}
@@ -36632,6 +36725,8 @@
method public int getMaxHeight();
method public int getMaxWidth();
method public android.widget.ImageView.ScaleType getScaleType();
+ method public android.content.res.ColorStateList getTint();
+ method public android.graphics.PorterDuff.Mode getTintMode();
method public int[] onCreateDrawableState(int);
method public void setAdjustViewBounds(boolean);
method public deprecated void setAlpha(int);
@@ -36653,6 +36748,8 @@
method public void setMaxHeight(int);
method public void setMaxWidth(int);
method public void setScaleType(android.widget.ImageView.ScaleType);
+ method public void setTint(android.content.res.ColorStateList);
+ method public void setTintMode(android.graphics.PorterDuff.Mode);
}
public static final class ImageView.ScaleType extends java.lang.Enum {
@@ -37025,11 +37122,19 @@
ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int);
ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int, int);
method public android.graphics.drawable.Drawable getIndeterminateDrawable();
+ method public android.content.res.ColorStateList getIndeterminateTint();
+ method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
method public android.view.animation.Interpolator getInterpolator();
method public synchronized int getMax();
method public synchronized int getProgress();
+ method public android.content.res.ColorStateList getProgressBackgroundTint();
+ method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
method public android.graphics.drawable.Drawable getProgressDrawable();
+ method public android.content.res.ColorStateList getProgressTint();
+ method public android.graphics.PorterDuff.Mode getProgressTintMode();
method public synchronized int getSecondaryProgress();
+ method public android.content.res.ColorStateList getSecondaryProgressTint();
+ method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
method public final synchronized void incrementProgressBy(int);
method public final synchronized void incrementSecondaryProgressBy(int);
method public synchronized boolean isIndeterminate();
@@ -37038,13 +37143,21 @@
method public synchronized void setIndeterminate(boolean);
method public void setIndeterminateDrawable(android.graphics.drawable.Drawable);
method public void setIndeterminateDrawableTiled(android.graphics.drawable.Drawable);
+ method public void setIndeterminateTint(android.content.res.ColorStateList);
+ method public void setIndeterminateTintMode(android.graphics.PorterDuff.Mode);
method public void setInterpolator(android.content.Context, int);
method public void setInterpolator(android.view.animation.Interpolator);
method public synchronized void setMax(int);
method public synchronized void setProgress(int);
+ method public void setProgressBackgroundTint(android.content.res.ColorStateList);
+ method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public void setProgressDrawable(android.graphics.drawable.Drawable);
method public void setProgressDrawableTiled(android.graphics.drawable.Drawable);
+ method public void setProgressTint(android.content.res.ColorStateList);
+ method public void setProgressTintMode(android.graphics.PorterDuff.Mode);
method public synchronized void setSecondaryProgress(int);
+ method public void setSecondaryProgressTint(android.content.res.ColorStateList);
+ method public void setSecondaryProgressTintMode(android.graphics.PorterDuff.Mode);
}
public class QuickContactBadge extends android.widget.ImageView implements android.view.View.OnClickListener {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 9c1f1d1..127b0fc 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -44,6 +44,7 @@
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.AndroidException;
import android.view.IWindowManager;
import android.view.View;
@@ -1717,11 +1718,7 @@
}
System.out.println("config: " + Configuration.resourceQualifierString(config));
- System.out.print("abi: " + Build.CPU_ABI);
- if (!Build.CPU_ABI2.isEmpty()) {
- System.out.print("," + Build.CPU_ABI2);
- }
- System.out.println();
+ System.out.println("abi: " + TextUtils.join(",", Build.SUPPORTED_ABIS));
} catch (RemoteException e) {
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 47047b8..f85a7dc 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -58,11 +58,13 @@
import java.util.Comparator;
import java.util.List;
import java.util.WeakHashMap;
+
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.android.internal.content.PackageHelper;
+import com.android.internal.util.ArrayUtils;
public final class Pm {
IPackageManager mPm;
@@ -1548,6 +1550,12 @@
if (info != null && info.applicationInfo != null) {
System.out.print("package:");
System.out.println(info.applicationInfo.sourceDir);
+ if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
+ for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
+ System.out.print("package:");
+ System.out.println(splitSourceDir);
+ }
+ }
}
} catch (RemoteException e) {
System.err.println(e.toString());
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f6883e2..90615d3 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -929,7 +929,8 @@
/**
* Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with
- * the attribute {@link android.R.attr#persistable} set true.
+ * the attribute {@link android.R.attr#persistableMode} set to
+ * <code>persistAcrossReboots</code>.
*
* @param savedInstanceState if the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
@@ -1012,8 +1013,9 @@
/**
* This is the same as {@link #onRestoreInstanceState(Bundle)} but is called for activities
- * created with the attribute {@link android.R.attr#persistable}. The {@link
- * android.os.PersistableBundle} passed came from the restored PersistableBundle first
+ * created with the attribute {@link android.R.attr#persistableMode} set to
+ * <code>persistAcrossReboots</code>. The {@link android.os.PersistableBundle} passed
+ * came from the restored PersistableBundle first
* saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
*
* <p>This method is called between {@link #onStart} and
@@ -1111,7 +1113,8 @@
/**
* This is the same as {@link #onPostCreate(Bundle)} but is called for activities
- * created with the attribute {@link android.R.attr#persistable}.
+ * created with the attribute {@link android.R.attr#persistableMode} set to
+ * <code>persistAcrossReboots</code>.
*
* @param savedInstanceState The data most recently supplied in {@link #onSaveInstanceState}
* @param persistentState The data caming from the PersistableBundle first
@@ -1352,10 +1355,10 @@
/**
* This is the same as {@link #onSaveInstanceState} but is called for activities
- * created with the attribute {@link android.R.attr#persistable}. The {@link
- * android.os.PersistableBundle} passed in will be saved and presented in
- * {@link #onCreate(Bundle, PersistableBundle)} the first time that this activity
- * is restarted following the next device reboot.
+ * created with the attribute {@link android.R.attr#persistableMode} set to
+ * <code>persistAcrossReboots</code>. The {@link android.os.PersistableBundle} passed
+ * in will be saved and presented in {@link #onCreate(Bundle, PersistableBundle)}
+ * the first time that this activity is restarted following the next device reboot.
*
* @param outState Bundle in which to place your saved state.
* @param outPersistentState State which will be saved across reboots.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ea46044..f5514f8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -191,11 +191,13 @@
/** Reference to singleton {@link ActivityThread} */
private static ActivityThread sCurrentActivityThread;
Instrumentation mInstrumentation;
+ String mInstrumentationPackageName = null;
String mInstrumentationAppDir = null;
- String mInstrumentationAppLibraryDir = null;
- String mInstrumentationAppPackage = null;
+ String[] mInstrumentationSplitAppDirs = null;
+ String mInstrumentationLibDir = null;
String mInstrumentedAppDir = null;
- String mInstrumentedAppLibraryDir = null;
+ String[] mInstrumentedSplitAppDirs = null;
+ String mInstrumentedLibDir = null;
boolean mSystemThread = false;
boolean mJitEnabled = false;
@@ -317,7 +319,7 @@
}
public boolean isPersistable() {
- return (activityInfo.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
+ return activityInfo.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS;
}
public String toString() {
@@ -1585,11 +1587,11 @@
/**
* Creates the top level resources for the given package.
*/
- Resources getTopLevelResources(String resDir, String[] overlayDirs, String[] libDirs,
- int displayId, Configuration overrideConfiguration,
+ Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
+ String[] libDirs, int displayId, Configuration overrideConfiguration,
LoadedApk pkgInfo) {
- return mResourcesManager.getTopLevelResources(resDir, overlayDirs, libDirs, displayId,
- overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
+ return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
+ displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
}
final Handler getHandler() {
@@ -4315,16 +4317,20 @@
+ data.instrumentationName);
}
+ mInstrumentationPackageName = ii.packageName;
mInstrumentationAppDir = ii.sourceDir;
- mInstrumentationAppLibraryDir = ii.nativeLibraryDir;
- mInstrumentationAppPackage = ii.packageName;
+ mInstrumentationSplitAppDirs = ii.splitSourceDirs;
+ mInstrumentationLibDir = ii.nativeLibraryDir;
mInstrumentedAppDir = data.info.getAppDir();
- mInstrumentedAppLibraryDir = data.info.getLibDir();
+ mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
+ mInstrumentedLibDir = data.info.getLibDir();
ApplicationInfo instrApp = new ApplicationInfo();
instrApp.packageName = ii.packageName;
instrApp.sourceDir = ii.sourceDir;
instrApp.publicSourceDir = ii.publicSourceDir;
+ instrApp.splitSourceDirs = ii.splitSourceDirs;
+ instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;
instrApp.dataDir = ii.dataDir;
instrApp.nativeLibraryDir = ii.nativeLibraryDir;
LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 0cccedc..c7030b0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -206,6 +206,9 @@
protected ResultReceiver mResultReceiver;
final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
final protected boolean mIsReturning;
+ private Runnable mPendingTransition;
+ private boolean mIsStartingTransition;
+
public ActivityTransitionCoordinator(Window window,
ArrayList<String> allSharedElementNames,
@@ -290,13 +293,17 @@
if (transition == null || views == null || views.isEmpty()) {
return null;
}
+ // Add the targets to a set containing transition so that transition
+ // remains unaffected. We don't want to modify the targets of transition itself.
TransitionSet set = new TransitionSet();
- set.addTransition(transition);
if (views != null) {
- for (View view: views) {
+ for (View view : views) {
set.addTarget(view);
}
}
+ // By adding the transition after addTarget, we prevent addTarget from
+ // affecting transition.
+ set.addTransition(transition);
return set;
}
@@ -523,7 +530,7 @@
* @param transitionArgs Bundle to store shared element placement information.
* @param tempBounds A temporary Rect for capturing the current location of views.
*/
- private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
+ protected static void captureSharedElementState(View view, String name, Bundle transitionArgs,
Rect tempBounds) {
Bundle sharedElementBundle = new Bundle();
tempBounds.set(0, 0, view.getWidth(), view.getHeight());
@@ -559,6 +566,32 @@
transitionArgs.putBundle(name, sharedElementBundle);
}
+
+ protected void startTransition(Runnable runnable) {
+ if (mIsStartingTransition) {
+ mPendingTransition = runnable;
+ } else {
+ mIsStartingTransition = true;
+ runnable.run();
+ }
+ }
+
+ protected void transitionStarted() {
+ mIsStartingTransition = false;
+ }
+
+ protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ mIsStartingTransition = false;
+ Runnable pending = mPendingTransition;
+ mPendingTransition = null;
+ if (pending != null) {
+ startTransition(pending);
+ }
+ }
+ }
+
private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
if (scaleType == SCALE_TYPE_VALUES[i]) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 84673d9..de0396e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -823,8 +823,10 @@
if (app.packageName.equals("system")) {
return mContext.mMainThread.getSystemContext().getResources();
}
+ final boolean sameUid = (app.uid == Process.myUid());
Resources r = mContext.mMainThread.getTopLevelResources(
- app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir,
+ sameUid ? app.sourceDir : app.publicSourceDir,
+ sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
app.resourceDirs, null, Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo);
if (r != null) {
return r;
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 89ee145..01a388f 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -16,36 +16,53 @@
package android.app;
+import com.android.internal.util.FastPrintWriter;
+
+import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.LogWriter;
-import com.android.internal.util.FastPrintWriter;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
final class BackStackState implements Parcelable {
final int[] mOps;
final int mTransition;
final int mTransitionStyle;
+ final int mCustomTransition;
+ final int mSceneRoot;
final String mName;
final int mIndex;
final int mBreadCrumbTitleRes;
final CharSequence mBreadCrumbTitleText;
final int mBreadCrumbShortTitleRes;
final CharSequence mBreadCrumbShortTitleText;
+ final ArrayList<String> mSharedElementSourceNames;
+ final ArrayList<String> mSharedElementTargetNames;
public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
int numRemoved = 0;
BackStackRecord.Op op = bse.mHead;
while (op != null) {
- if (op.removed != null) numRemoved += op.removed.size();
+ if (op.removed != null) {
+ numRemoved += op.removed.size();
+ }
op = op.next;
}
- mOps = new int[bse.mNumOp*7 + numRemoved];
+ mOps = new int[bse.mNumOp * 7 + numRemoved];
if (!bse.mAddToBackStack) {
throw new IllegalStateException("Not on back stack");
@@ -63,7 +80,7 @@
if (op.removed != null) {
final int N = op.removed.size();
mOps[pos++] = N;
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
mOps[pos++] = op.removed.get(i).mIndex;
}
} else {
@@ -79,6 +96,10 @@
mBreadCrumbTitleText = bse.mBreadCrumbTitleText;
mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes;
mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText;
+ mCustomTransition = bse.mCustomTransition;
+ mSceneRoot = bse.mSceneRoot;
+ mSharedElementSourceNames = bse.mSharedElementSourceNames;
+ mSharedElementTargetNames = bse.mSharedElementTargetNames;
}
public BackStackState(Parcel in) {
@@ -91,6 +112,10 @@
mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mBreadCrumbShortTitleRes = in.readInt();
mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mCustomTransition = in.readInt();
+ mSceneRoot = in.readInt();
+ mSharedElementSourceNames = in.createStringArrayList();
+ mSharedElementTargetNames = in.createStringArrayList();
}
public BackStackRecord instantiate(FragmentManagerImpl fm) {
@@ -100,8 +125,10 @@
while (pos < mOps.length) {
BackStackRecord.Op op = new BackStackRecord.Op();
op.cmd = mOps[pos++];
- if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
- "Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(FragmentManagerImpl.TAG,
+ "Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
+ }
int findex = mOps[pos++];
if (findex >= 0) {
Fragment f = fm.mActive.get(findex);
@@ -116,9 +143,11 @@
final int N = mOps[pos++];
if (N > 0) {
op.removed = new ArrayList<Fragment>(N);
- for (int i=0; i<N; i++) {
- if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
- "Instantiate " + bse + " set remove fragment #" + mOps[pos]);
+ for (int i = 0; i < N; i++) {
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(FragmentManagerImpl.TAG,
+ "Instantiate " + bse + " set remove fragment #" + mOps[pos]);
+ }
Fragment r = fm.mActive.get(mOps[pos++]);
op.removed.add(r);
}
@@ -135,6 +164,10 @@
bse.mBreadCrumbTitleText = mBreadCrumbTitleText;
bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes;
bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText;
+ bse.mCustomTransition = mCustomTransition;
+ bse.mSceneRoot = mSceneRoot;
+ bse.mSharedElementSourceNames = mSharedElementSourceNames;
+ bse.mSharedElementTargetNames = mSharedElementTargetNames;
bse.bumpBackStackNesting(1);
return bse;
}
@@ -153,6 +186,10 @@
TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0);
dest.writeInt(mBreadCrumbShortTitleRes);
TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0);
+ dest.writeInt(mCustomTransition);
+ dest.writeInt(mSceneRoot);
+ dest.writeStringList(mSharedElementSourceNames);
+ dest.writeStringList(mSharedElementTargetNames);
}
public static final Parcelable.Creator<BackStackState> CREATOR
@@ -217,6 +254,11 @@
int mBreadCrumbShortTitleRes;
CharSequence mBreadCrumbShortTitleText;
+ int mCustomTransition;
+ int mSceneRoot;
+ ArrayList<String> mSharedElementSourceNames;
+ ArrayList<String> mSharedElementTargetNames;
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
@@ -240,78 +282,112 @@
void dump(String prefix, PrintWriter writer, boolean full) {
if (full) {
- writer.print(prefix); writer.print("mName="); writer.print(mName);
- writer.print(" mIndex="); writer.print(mIndex);
- writer.print(" mCommitted="); writer.println(mCommitted);
+ writer.print(prefix);
+ writer.print("mName=");
+ writer.print(mName);
+ writer.print(" mIndex=");
+ writer.print(mIndex);
+ writer.print(" mCommitted=");
+ writer.println(mCommitted);
if (mTransition != FragmentTransaction.TRANSIT_NONE) {
- writer.print(prefix); writer.print("mTransition=#");
- writer.print(Integer.toHexString(mTransition));
- writer.print(" mTransitionStyle=#");
- writer.println(Integer.toHexString(mTransitionStyle));
+ writer.print(prefix);
+ writer.print("mTransition=#");
+ writer.print(Integer.toHexString(mTransition));
+ writer.print(" mTransitionStyle=#");
+ writer.println(Integer.toHexString(mTransitionStyle));
}
- if (mEnterAnim != 0 || mExitAnim !=0) {
- writer.print(prefix); writer.print("mEnterAnim=#");
- writer.print(Integer.toHexString(mEnterAnim));
- writer.print(" mExitAnim=#");
- writer.println(Integer.toHexString(mExitAnim));
+ if (mEnterAnim != 0 || mExitAnim != 0) {
+ writer.print(prefix);
+ writer.print("mEnterAnim=#");
+ writer.print(Integer.toHexString(mEnterAnim));
+ writer.print(" mExitAnim=#");
+ writer.println(Integer.toHexString(mExitAnim));
}
- if (mPopEnterAnim != 0 || mPopExitAnim !=0) {
- writer.print(prefix); writer.print("mPopEnterAnim=#");
- writer.print(Integer.toHexString(mPopEnterAnim));
- writer.print(" mPopExitAnim=#");
- writer.println(Integer.toHexString(mPopExitAnim));
+ if (mPopEnterAnim != 0 || mPopExitAnim != 0) {
+ writer.print(prefix);
+ writer.print("mPopEnterAnim=#");
+ writer.print(Integer.toHexString(mPopEnterAnim));
+ writer.print(" mPopExitAnim=#");
+ writer.println(Integer.toHexString(mPopExitAnim));
}
if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) {
- writer.print(prefix); writer.print("mBreadCrumbTitleRes=#");
- writer.print(Integer.toHexString(mBreadCrumbTitleRes));
- writer.print(" mBreadCrumbTitleText=");
- writer.println(mBreadCrumbTitleText);
+ writer.print(prefix);
+ writer.print("mBreadCrumbTitleRes=#");
+ writer.print(Integer.toHexString(mBreadCrumbTitleRes));
+ writer.print(" mBreadCrumbTitleText=");
+ writer.println(mBreadCrumbTitleText);
}
if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) {
- writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#");
- writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
- writer.print(" mBreadCrumbShortTitleText=");
- writer.println(mBreadCrumbShortTitleText);
+ writer.print(prefix);
+ writer.print("mBreadCrumbShortTitleRes=#");
+ writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
+ writer.print(" mBreadCrumbShortTitleText=");
+ writer.println(mBreadCrumbShortTitleText);
}
}
if (mHead != null) {
- writer.print(prefix); writer.println("Operations:");
+ writer.print(prefix);
+ writer.println("Operations:");
String innerPrefix = prefix + " ";
Op op = mHead;
int num = 0;
while (op != null) {
String cmdStr;
switch (op.cmd) {
- case OP_NULL: cmdStr="NULL"; break;
- case OP_ADD: cmdStr="ADD"; break;
- case OP_REPLACE: cmdStr="REPLACE"; break;
- case OP_REMOVE: cmdStr="REMOVE"; break;
- case OP_HIDE: cmdStr="HIDE"; break;
- case OP_SHOW: cmdStr="SHOW"; break;
- case OP_DETACH: cmdStr="DETACH"; break;
- case OP_ATTACH: cmdStr="ATTACH"; break;
- default: cmdStr="cmd=" + op.cmd; break;
+ case OP_NULL:
+ cmdStr = "NULL";
+ break;
+ case OP_ADD:
+ cmdStr = "ADD";
+ break;
+ case OP_REPLACE:
+ cmdStr = "REPLACE";
+ break;
+ case OP_REMOVE:
+ cmdStr = "REMOVE";
+ break;
+ case OP_HIDE:
+ cmdStr = "HIDE";
+ break;
+ case OP_SHOW:
+ cmdStr = "SHOW";
+ break;
+ case OP_DETACH:
+ cmdStr = "DETACH";
+ break;
+ case OP_ATTACH:
+ cmdStr = "ATTACH";
+ break;
+ default:
+ cmdStr = "cmd=" + op.cmd;
+ break;
}
- writer.print(prefix); writer.print(" Op #"); writer.print(num);
- writer.print(": "); writer.print(cmdStr);
- writer.print(" "); writer.println(op.fragment);
+ writer.print(prefix);
+ writer.print(" Op #");
+ writer.print(num);
+ writer.print(": ");
+ writer.print(cmdStr);
+ writer.print(" ");
+ writer.println(op.fragment);
if (full) {
if (op.enterAnim != 0 || op.exitAnim != 0) {
- writer.print(innerPrefix); writer.print("enterAnim=#");
- writer.print(Integer.toHexString(op.enterAnim));
- writer.print(" exitAnim=#");
- writer.println(Integer.toHexString(op.exitAnim));
+ writer.print(innerPrefix);
+ writer.print("enterAnim=#");
+ writer.print(Integer.toHexString(op.enterAnim));
+ writer.print(" exitAnim=#");
+ writer.println(Integer.toHexString(op.exitAnim));
}
if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
- writer.print(innerPrefix); writer.print("popEnterAnim=#");
- writer.print(Integer.toHexString(op.popEnterAnim));
- writer.print(" popExitAnim=#");
- writer.println(Integer.toHexString(op.popExitAnim));
+ writer.print(innerPrefix);
+ writer.print("popEnterAnim=#");
+ writer.print(Integer.toHexString(op.popEnterAnim));
+ writer.print(" popExitAnim=#");
+ writer.println(Integer.toHexString(op.popExitAnim));
}
}
if (op.removed != null && op.removed.size() > 0) {
- for (int i=0; i<op.removed.size(); i++) {
+ for (int i = 0; i < op.removed.size(); i++) {
writer.print(innerPrefix);
if (op.removed.size() == 1) {
writer.print("Removed: ");
@@ -319,8 +395,10 @@
if (i == 0) {
writer.println("Removed:");
}
- writer.print(innerPrefix); writer.print(" #"); writer.print(i);
- writer.print(": ");
+ writer.print(innerPrefix);
+ writer.print(" #");
+ writer.print(i);
+ writer.print(": ");
}
writer.println(op.removed.get(i));
}
@@ -494,6 +572,51 @@
return this;
}
+ @Override
+ public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) {
+ mSceneRoot = sceneRootId;
+ mCustomTransition = transitionId;
+ return this;
+ }
+
+ @Override
+ public FragmentTransaction setSharedElement(View sharedElement, String name) {
+ String viewName = sharedElement.getViewName();
+ if (viewName == null) {
+ throw new IllegalArgumentException("Unique viewNames are required for all" +
+ " sharedElements");
+ }
+ mSharedElementSourceNames = new ArrayList<String>(1);
+ mSharedElementSourceNames.add(viewName);
+
+ mSharedElementTargetNames = new ArrayList<String>(1);
+ mSharedElementTargetNames.add(name);
+ return this;
+ }
+
+ @Override
+ public FragmentTransaction setSharedElements(Pair<View, String>... sharedElements) {
+ if (sharedElements == null || sharedElements.length == 0) {
+ mSharedElementSourceNames = null;
+ mSharedElementTargetNames = null;
+ } else {
+ ArrayList<String> sourceNames = new ArrayList<String>(sharedElements.length);
+ ArrayList<String> targetNames = new ArrayList<String>(sharedElements.length);
+ for (int i = 0; i < sharedElements.length; i++) {
+ String viewName = sharedElements[i].first.getViewName();
+ if (viewName == null) {
+ throw new IllegalArgumentException("Unique viewNames are required for all" +
+ " sharedElements");
+ }
+ sourceNames.add(viewName);
+ targetNames.add(sharedElements[i].second);
+ }
+ mSharedElementSourceNames = sourceNames;
+ mSharedElementTargetNames = targetNames;
+ }
+ return this;
+ }
+
public FragmentTransaction setTransitionStyle(int styleRes) {
mTransitionStyle = styleRes;
return this;
@@ -550,21 +673,27 @@
if (!mAddToBackStack) {
return;
}
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting in " + this
- + " by " + amt);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Bump nesting in " + this
+ + " by " + amt);
+ }
Op op = mHead;
while (op != null) {
if (op.fragment != null) {
op.fragment.mBackStackNesting += amt;
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
- + op.fragment + " to " + op.fragment.mBackStackNesting);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Bump nesting of "
+ + op.fragment + " to " + op.fragment.mBackStackNesting);
+ }
}
if (op.removed != null) {
- for (int i=op.removed.size()-1; i>=0; i--) {
+ for (int i = op.removed.size() - 1; i >= 0; i--) {
Fragment r = op.removed.get(i);
r.mBackStackNesting += amt;
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
- + r + " to " + r.mBackStackNesting);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Bump nesting of "
+ + r + " to " + r.mBackStackNesting);
+ }
}
}
op = op.next;
@@ -578,9 +707,11 @@
public int commitAllowingStateLoss() {
return commitInternal(true);
}
-
+
int commitInternal(boolean allowStateLoss) {
- if (mCommitted) throw new IllegalStateException("commit already called");
+ if (mCommitted) {
+ throw new IllegalStateException("commit already called");
+ }
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
@@ -597,9 +728,11 @@
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
-
+
public void run() {
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Run: " + this);
+ }
if (mAddToBackStack) {
if (mIndex < 0) {
@@ -609,6 +742,9 @@
bumpBackStackNesting(1);
+ TransitionState state = beginTransition(mSharedElementSourceNames,
+ mSharedElementTargetNames);
+
Op op = mHead;
while (op != null) {
switch (op.cmd) {
@@ -616,14 +752,17 @@
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
- } break;
+ }
+ break;
case OP_REPLACE: {
Fragment f = op.fragment;
if (mManager.mAdded != null) {
- for (int i=0; i<mManager.mAdded.size(); i++) {
+ for (int i = 0; i < mManager.mAdded.size(); i++) {
Fragment old = mManager.mAdded.get(i);
- if (FragmentManagerImpl.DEBUG) Log.v(TAG,
- "OP_REPLACE: adding=" + f + " old=" + old);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG,
+ "OP_REPLACE: adding=" + f + " old=" + old);
+ }
if (f == null || old.mContainerId == f.mContainerId) {
if (old == f) {
op.fragment = f = null;
@@ -635,8 +774,10 @@
old.mNextAnim = op.exitAnim;
if (mAddToBackStack) {
old.mBackStackNesting += 1;
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
- + old + " to " + old.mBackStackNesting);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Bump nesting of "
+ + old + " to " + old.mBackStackNesting);
+ }
}
mManager.removeFragment(old, mTransition, mTransitionStyle);
}
@@ -647,32 +788,38 @@
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
- } break;
+ }
+ break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.removeFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.hideFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.showFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.detachFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.attachFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
@@ -687,9 +834,174 @@
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
+
+ if (state != null) {
+ updateTransitionEndState(state, mSharedElementTargetNames);
+ }
}
- public void popFromBackStack(boolean doStateMove) {
+ private TransitionState beginTransition(ArrayList<String> sourceNames,
+ ArrayList<String> targetNames) {
+ if (mCustomTransition <= 0 || mSceneRoot <= 0) {
+ return null;
+ }
+ View rootView = mManager.mContainer.findViewById(mSceneRoot);
+ if (!(rootView instanceof ViewGroup)) {
+ throw new IllegalArgumentException("SceneRoot is not a ViewGroup");
+ }
+ TransitionState state = new TransitionState();
+ // get Transition scene root and create Transitions
+ state.sceneRoot = (ViewGroup) rootView;
+ state.sceneRoot.captureTransitioningViews(state.transitioningViews);
+
+ state.exitTransition = TransitionInflater.from(mManager.mActivity)
+ .inflateTransition(mCustomTransition);
+ state.sharedElementTransition = TransitionInflater.from(mManager.mActivity)
+ .inflateTransition(mCustomTransition);
+ state.enterTransition = TransitionInflater.from(mManager.mActivity)
+ .inflateTransition(mCustomTransition);
+ // Adding a non-existent target view makes sure that the transitions don't target
+ // any views by default. They'll only target the views we tell add. If we don't
+ // add any, then no views will be targeted.
+ View nonExistentView = new View(mManager.mActivity);
+ state.enterTransition.addTarget(nonExistentView);
+ state.exitTransition.addTarget(nonExistentView);
+ state.sharedElementTransition.addTarget(nonExistentView);
+
+ setSharedElementEpicenter(state.enterTransition, state);
+
+ state.excludingTransition = new TransitionSet()
+ .addTransition(state.exitTransition)
+ .addTransition(state.enterTransition);
+
+ if (sourceNames != null) {
+ // Map shared elements.
+ state.sceneRoot.findNamedViews(state.namedViews);
+ state.namedViews.retainAll(sourceNames);
+ View epicenterView = state.namedViews.get(sourceNames.get(0));
+ if (epicenterView != null) {
+ // The epicenter is only the first shared element.
+ setEpicenter(state.exitTransition, epicenterView);
+ setEpicenter(state.sharedElementTransition, epicenterView);
+ }
+ state.transitioningViews.removeAll(state.namedViews.values());
+ state.excludingTransition.addTransition(state.sharedElementTransition);
+ addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
+ }
+
+ // Adds the (maybe) exiting views, not including the shared element.
+ // If some stay, that's ok.
+ addTransitioningViews(state.exitTransition, state.transitioningViews);
+
+ // Prepare for shared element name mapping. This could be chained in the case
+ // of popping several back stack states.
+ state.excludingTransition.setNameOverrides(new ArrayMap<String, String>());
+ setNameOverrides(state, sourceNames, targetNames);
+
+ // Don't include any subtree in the views that are hidden when capturing the
+ // view hierarchy transitions. They should be as if not there.
+ excludeHiddenFragments(state, true);
+
+ TransitionManager.beginDelayedTransition(state.sceneRoot, state.excludingTransition);
+ return state;
+ }
+
+ private void updateTransitionEndState(TransitionState state, ArrayList<String> names) {
+ // Find all views that are entering.
+ ArrayList<View> enteringViews = new ArrayList<View>();
+ state.sceneRoot.captureTransitioningViews(enteringViews);
+ enteringViews.removeAll(state.transitioningViews);
+
+ if (names != null) {
+ // find all shared elements.
+ state.namedViews.clear();
+ state.sceneRoot.findNamedViews(state.namedViews);
+ state.namedViews.retainAll(names);
+ if (!state.namedViews.isEmpty()) {
+ enteringViews.removeAll(state.namedViews.values());
+ addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
+ // now we know the epicenter of the entering transition.
+ state.mEnteringEpicenterView = state.namedViews.get(names.get(0));
+ }
+ }
+
+ // Add all entering views to the enter transition.
+ addTransitioningViews(state.enterTransition, enteringViews);
+
+ // Don't allow capturing state for the newly-hidden fragments.
+ excludeHiddenFragments(state, false);
+
+ // Allow capturing state for the newly-shown fragments
+ includeVisibleFragments(state.excludingTransition);
+ }
+
+ private void addTransitioningViews(Transition transition, Collection<View> views) {
+ if (views.isEmpty()) {
+ // Add a view so that we can modify the valid views at the end of the
+ // fragment transaction.
+ transition.addTarget(new View(mManager.mActivity));
+ } else {
+ for (View view : views) {
+ transition.addTarget(view);
+ }
+ }
+ }
+
+ private void excludeHiddenFragments(TransitionState state, boolean forceExclude) {
+ if (mManager.mAdded != null) {
+ for (int i = 0; i < mManager.mAdded.size(); i++) {
+ Fragment fragment = mManager.mAdded.get(i);
+ if (fragment.mView != null && fragment.mHidden
+ && (forceExclude || !state.hiddenViews.contains(fragment.mView))) {
+ state.excludingTransition.excludeTarget(fragment.mView, true);
+ state.hiddenViews.add(fragment.mView);
+ }
+ }
+ }
+ if (forceExclude && state.hiddenViews.isEmpty()) {
+ state.excludingTransition.excludeTarget(new View(mManager.mActivity), true);
+ }
+ }
+
+ private void includeVisibleFragments(Transition transition) {
+ if (mManager.mAdded != null) {
+ for (int i = 0; i < mManager.mAdded.size(); i++) {
+ Fragment fragment = mManager.mAdded.get(i);
+ if (fragment.mView != null && !fragment.mHidden) {
+ transition.excludeTarget(fragment.mView, false);
+ }
+ }
+ }
+ }
+
+ private static void setEpicenter(Transition transition, View view) {
+ final Rect epicenter = new Rect();
+ view.getBoundsOnScreen(epicenter);
+
+ transition.setEpicenterCallback(new Transition.EpicenterCallback() {
+ @Override
+ public Rect onGetEpicenter(Transition transition) {
+ return epicenter;
+ }
+ });
+ }
+
+ private void setSharedElementEpicenter(Transition transition, final TransitionState state) {
+ transition.setEpicenterCallback(new Transition.EpicenterCallback() {
+ private Rect mEpicenter;
+
+ @Override
+ public Rect onGetEpicenter(Transition transition) {
+ if (mEpicenter == null && state.mEnteringEpicenterView != null) {
+ mEpicenter = new Rect();
+ state.mEnteringEpicenterView.getBoundsOnScreen(mEpicenter);
+ }
+ return mEpicenter;
+ }
+ });
+ }
+
+ public TransitionState popFromBackStack(boolean doStateMove, TransitionState state) {
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "popFromBackStack: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
@@ -698,6 +1010,12 @@
pw.flush();
}
+ if (state == null) {
+ state = beginTransition(mSharedElementTargetNames, mSharedElementSourceNames);
+ } else {
+ setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
+ }
+
bumpBackStackNesting(-1);
Op op = mTail;
@@ -709,7 +1027,8 @@
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),
mTransitionStyle);
- } break;
+ }
+ break;
case OP_REPLACE: {
Fragment f = op.fragment;
if (f != null) {
@@ -719,42 +1038,48 @@
mTransitionStyle);
}
if (op.removed != null) {
- for (int i=0; i<op.removed.size(); i++) {
+ for (int i = 0; i < op.removed.size(); i++) {
Fragment old = op.removed.get(i);
old.mNextAnim = op.popEnterAnim;
mManager.addFragment(old, false);
}
}
- } break;
+ }
+ break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = op.popEnterAnim;
mManager.addFragment(f, false);
- } break;
+ }
+ break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim = op.popEnterAnim;
mManager.showFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
- } break;
+ }
+ break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim = op.popExitAnim;
mManager.hideFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
- } break;
+ }
+ break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim = op.popEnterAnim;
mManager.attachFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
- } break;
+ }
+ break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim = op.popExitAnim;
mManager.detachFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
- } break;
+ }
+ break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
@@ -766,12 +1091,39 @@
if (doStateMove) {
mManager.moveToState(mManager.mCurState,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
+ if (state != null) {
+ updateTransitionEndState(state, mSharedElementSourceNames);
+ state = null;
+ }
}
if (mIndex >= 0) {
mManager.freeBackStackIndex(mIndex);
mIndex = -1;
}
+ return state;
+ }
+
+ private static void setNameOverride(Transition transition, String source, String target) {
+ ArrayMap<String, String> overrides = transition.getNameOverrides();
+ for (int index = 0; index < overrides.size(); index++) {
+ if (source.equals(overrides.valueAt(index))) {
+ overrides.setValueAt(index, target);
+ return;
+ }
+ }
+ overrides.put(source, target);
+ }
+
+ private static void setNameOverrides(TransitionState state, ArrayList<String> sourceNames,
+ ArrayList<String> targetNames) {
+ if (sourceNames != null) {
+ for (int i = 0; i < sourceNames.size(); i++) {
+ String source = sourceNames.get(i);
+ String target = targetNames.get(i);
+ setNameOverride(state.excludingTransition, source, target);
+ }
+ }
}
public String getName() {
@@ -789,4 +1141,16 @@
public boolean isEmpty() {
return mNumOp == 0;
}
+
+ public class TransitionState {
+ public ArrayList<View> hiddenViews = new ArrayList<View>();
+ public ArrayList<View> transitioningViews = new ArrayList<View>();
+ public ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
+ public Transition exitTransition;
+ public Transition sharedElementTransition;
+ public Transition enterTransition;
+ public TransitionSet excludingTransition;
+ public ViewGroup sceneRoot;
+ public View mEnteringEpicenterView;
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ab3bb49..425a140 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -115,9 +115,8 @@
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.service.fingerprint.IFingerprintService;
import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
-import android.service.fingerprint.FingerprintService;
import android.telecomm.TelecommManager;
import android.telephony.TelephonyManager;
import android.content.ClipboardManager;
@@ -466,11 +465,6 @@
return new KeyguardManager();
}});
- registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new FingerprintManager(ctx);
- }});
-
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
@@ -519,6 +513,9 @@
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(POWER_SERVICE);
IPowerManager service = IPowerManager.Stub.asInterface(b);
+ if (service == null) {
+ Log.wtf(TAG, "Failed to get power manager service.");
+ }
return new PowerManager(ctx.getOuterContext(),
service, ctx.mMainThread.getHandler());
}});
@@ -690,6 +687,7 @@
return new MediaSessionManager(ctx);
}
});
+
registerService(TRUST_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(TRUST_SERVICE);
@@ -697,6 +695,14 @@
}
});
+ registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder binder = ServiceManager.getService(FINGERPRINT_SERVICE);
+ IFingerprintService service = IFingerprintService.Stub.asInterface(binder);
+ return new FingerprintManager(ctx.getOuterContext(), service);
+ }
+ });
+
registerService(TV_INPUT_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder iBinder = ServiceManager.getService(TV_INPUT_SERVICE);
@@ -2187,10 +2193,10 @@
|| overrideConfiguration != null
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
- resources = mResourcesManager.getTopLevelResources(
- packageInfo.getResDir(), packageInfo.getOverlayDirs(),
- packageInfo.getApplicationInfo().sharedLibraryFiles,
- displayId, overrideConfiguration, compatInfo, activityToken);
+ resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
+ packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
+ packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
+ overrideConfiguration, compatInfo, activityToken);
}
}
mResources = resources;
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index f54cb87..365cc8e8 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -106,7 +106,16 @@
private void sendSharedElementDestination() {
ViewGroup decor = getDecor();
- if (!decor.isLayoutRequested()) {
+ boolean allReady = !decor.isLayoutRequested();
+ if (allReady) {
+ for (int i = 0; i < mSharedElements.size(); i++) {
+ if (mSharedElements.get(i).isLayoutRequested()) {
+ allReady = false;
+ break;
+ }
+ }
+ }
+ if (allReady) {
Bundle state = captureSharedElementState();
mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
} else {
@@ -115,10 +124,15 @@
@Override
public boolean onPreDraw() {
getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ Bundle state = captureSharedElementState();
+ mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
return true;
}
});
}
+ if (allowOverlappingTransitions()) {
+ startEnterTransitionOnly();
+ }
}
private static SharedElementListener getListener(Activity activity, boolean isReturning) {
@@ -207,24 +221,6 @@
}
}
- protected void onTakeSharedElements() {
- if (!mIsReadyForTransition || mSharedElementsBundle == null) {
- return;
- }
- final Bundle sharedElementState = mSharedElementsBundle;
- mSharedElementsBundle = null;
- getDecor().getViewTreeObserver()
- .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
- startSharedElementTransition(sharedElementState);
- return false;
- }
- });
- getDecor().invalidate();
- }
-
private void startSharedElementTransition(Bundle sharedElementState) {
setEpicenter();
// Remove rejected shared elements
@@ -242,7 +238,7 @@
setSharedElementState(sharedElementState, sharedElementSnapshots);
requestLayoutForSharedElements();
- boolean startEnterTransition = allowOverlappingTransitions();
+ boolean startEnterTransition = allowOverlappingTransitions() && !mIsReturning;
boolean startSharedElementTransition = true;
Transition transition = beginTransition(startEnterTransition, startSharedElementTransition);
@@ -258,6 +254,29 @@
mResultReceiver = null; // all done sending messages.
}
+ private void onTakeSharedElements() {
+ if (!mIsReadyForTransition || mSharedElementsBundle == null) {
+ return;
+ }
+ final Bundle sharedElementState = mSharedElementsBundle;
+ mSharedElementsBundle = null;
+ getDecor().getViewTreeObserver()
+ .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ startSharedElementTransition(sharedElementState);
+ }
+ });
+ return false;
+ }
+ });
+ getDecor().invalidate();
+ }
+
private void requestLayoutForSharedElements() {
int numSharedElements = mSharedElements.size();
for (int i = 0; i < numSharedElements; i++) {
@@ -282,9 +301,10 @@
if (transition == null) {
sharedElementTransitionStarted();
} else {
- transition.addListener(new Transition.TransitionListenerAdapter() {
+ transition.addListener(new ContinueTransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
+ super.onTransitionStart(transition);
transition.removeListener(this);
sharedElementTransitionStarted();
}
@@ -292,12 +312,17 @@
}
}
if (transition != null) {
+ if (sharedElementTransition == null) {
+ transition.addListener(new ContinueTransitionListener());
+ }
TransitionManager.beginDelayedTransition(getDecor(), transition);
if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
mSharedElements.get(0).invalidate();
} else if (startEnterTransition && !mTransitioningViews.isEmpty()) {
mTransitioningViews.get(0).invalidate();
}
+ } else {
+ transitionStarted();
}
return transition;
}
@@ -388,11 +413,21 @@
protected void onRemoteExitTransitionComplete() {
if (!allowOverlappingTransitions()) {
- boolean startEnterTransition = true;
- boolean startSharedElementTransition = false;
- Transition transition = beginTransition(startEnterTransition,
- startSharedElementTransition);
- startEnterTransition(transition);
+ startEnterTransitionOnly();
}
}
+
+ private void startEnterTransitionOnly() {
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ setEpicenter();
+ boolean startEnterTransition = true;
+ boolean startSharedElementTransition = false;
+ Transition transition = beginTransition(startEnterTransition,
+ startSharedElementTransition);
+ startEnterTransition(transition);
+ }
+ });
+ }
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 8d5b8317..9f3dbdc 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -19,6 +19,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Intent;
+import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -27,6 +28,7 @@
import android.transition.Transition;
import android.transition.TransitionManager;
import android.view.View;
+import android.view.ViewGroupOverlay;
import android.view.ViewTreeObserver;
import java.util.ArrayList;
@@ -60,10 +62,10 @@
private boolean mIsHidden;
- private boolean mExitTransitionStarted;
-
private Bundle mExitSharedElementBundle;
+ private ArrayList<View> mSharedElementSnapshots;
+
public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
ArrayList<String> accepted, ArrayList<String> mapped, boolean isReturning) {
super(activity.getWindow(), names, accepted, mapped, getListener(activity, isReturning),
@@ -106,30 +108,83 @@
break;
case MSG_SHARED_ELEMENT_DESTINATION:
mExitSharedElementBundle = resultData;
- if (mExitTransitionStarted) {
- startSharedElementExit();
- }
+ sharedElementExitBack();
break;
}
}
- private void startSharedElementExit() {
+ private void sharedElementExitBack() {
if (!mSharedElements.isEmpty() && getSharedElementTransition() != null) {
- Transition transition = getSharedElementExitTransition();
- TransitionManager.beginDelayedTransition(getDecor(), transition);
- ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
- mSharedElementNames);
- setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
+ startTransition(new Runnable() {
+ public void run() {
+ startSharedElementExit();
+ }
+ });
}
}
+ private void startSharedElementExit() {
+ Transition transition = getSharedElementExitTransition();
+ final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
+ mSharedElementNames);
+ mSharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames);
+ transition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ setViewVisibility(mSharedElements, View.INVISIBLE);
+ ViewGroupOverlay overlay = getDecor().getOverlay();
+ if (mSharedElementSnapshots != null) {
+ for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
+ overlay.add(mSharedElementSnapshots.get(i));
+ }
+ }
+ }
+ });
+ getDecor().getViewTreeObserver()
+ .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
+ return true;
+ }
+ });
+ TransitionManager.beginDelayedTransition(getDecor(), transition);
+ getDecor().invalidate();
+ }
+
+ private static ArrayList<View> copySnapshots(ArrayList<View> snapshots) {
+ ArrayList<View> copy = new ArrayList<View>(snapshots.size());
+ for (int i = 0; i < snapshots.size(); i++) {
+ View view = snapshots.get(i);
+ View viewCopy = new View(view.getContext());
+ viewCopy.setBackground(view.getBackground());
+ copy.add(viewCopy);
+ }
+ return copy;
+ }
+
private void hideSharedElements() {
- setViewVisibility(mSharedElements, View.INVISIBLE);
+ if (!mIsHidden) {
+ setViewVisibility(mSharedElements, View.INVISIBLE);
+ }
+ if (mSharedElementSnapshots != null) {
+ ViewGroupOverlay overlay = getDecor().getOverlay();
+ for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
+ overlay.remove(mSharedElementSnapshots.get(i));
+ }
+ mSharedElementSnapshots = null;
+ }
finishIfNecessary();
}
public void startExit() {
- beginTransitions();
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ beginTransitions();
+ }
+ });
setViewVisibility(mTransitioningViews, View.INVISIBLE);
}
@@ -159,29 +214,25 @@
}
}
}, options);
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ startExitTransition();
+ }
+ });
+ }
+
+ private void startExitTransition() {
Transition sharedElementTransition = mSharedElements.isEmpty()
? null : getSharedElementTransition();
if (sharedElementTransition == null) {
sharedElementTransitionComplete();
}
- Transition transition = mergeTransitions(sharedElementTransition, getExitTransition());
- if (transition == null) {
- mExitTransitionStarted = true;
- } else {
+ Transition transition = mergeTransitions(sharedElementTransition,
+ getExitTransition());
+ if (transition != null) {
TransitionManager.beginDelayedTransition(getDecor(), transition);
setViewVisibility(mTransitioningViews, View.INVISIBLE);
- getDecor().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
- mExitTransitionStarted = true;
- if (mExitSharedElementBundle != null) {
- startSharedElementExit();
- }
- notifyComplete();
- return true;
- }
- });
}
}
@@ -212,7 +263,7 @@
if (viewsTransition == null) {
exitTransitionComplete();
} else {
- viewsTransition.addListener(new Transition.TransitionListenerAdapter() {
+ viewsTransition.addListener(new ContinueTransitionListener() {
@Override
public void onTransitionEnd(Transition transition) {
exitTransitionComplete();
@@ -238,7 +289,7 @@
if (sharedElementTransition == null) {
sharedElementTransitionComplete();
} else {
- sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
+ sharedElementTransition.addListener(new ContinueTransitionListener() {
@Override
public void onTransitionEnd(Transition transition) {
sharedElementTransitionComplete();
@@ -257,7 +308,6 @@
Transition viewsTransition = getExitTransition();
Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
- mExitTransitionStarted = true;
if (transition != null) {
TransitionManager.beginDelayedTransition(getDecor(), transition);
}
@@ -269,15 +319,31 @@
}
protected boolean isReadyToNotify() {
- return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady
- && mExitTransitionStarted;
+ return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
}
private void sharedElementTransitionComplete() {
- mSharedElementBundle = captureSharedElementState();
+ mSharedElementBundle = mExitSharedElementBundle == null
+ ? captureSharedElementState() : captureExitSharedElementsState();
notifyComplete();
}
+ private Bundle captureExitSharedElementsState() {
+ Bundle bundle = new Bundle();
+ Rect bounds = new Rect();
+ for (int i = 0; i < mSharedElementNames.size(); i++) {
+ String name = mSharedElementNames.get(i);
+ Bundle sharedElementState = mExitSharedElementBundle.getBundle(name);
+ if (sharedElementState != null) {
+ bundle.putBundle(name, sharedElementState);
+ } else {
+ View view = mSharedElements.get(i);
+ captureSharedElementState(view, name, bundle, bounds);
+ }
+ }
+ return bundle;
+ }
+
protected void notifyComplete() {
if (isReadyToNotify()) {
if (!mSharedElementNotified) {
@@ -294,8 +360,7 @@
}
private void finishIfNecessary() {
- if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty()
- || mSharedElements.get(0).getVisibility() == View.INVISIBLE)) {
+ if (mIsReturning && mExitNotified && mActivity != null && mSharedElementSnapshots == null) {
mActivity.finish();
mActivity.overridePendingTransition(0, 0);
mActivity = null;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 76f9d97..b8f1962 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1494,7 +1494,7 @@
return false;
}
final BackStackRecord bss = mBackStack.remove(last);
- bss.popFromBackStack(true);
+ bss.popFromBackStack(true, null);
reportBackStackChanged();
} else {
int index = -1;
@@ -1538,9 +1538,10 @@
states.add(mBackStack.remove(i));
}
final int LAST = states.size()-1;
+ BackStackRecord.TransitionState state = null;
for (int i=0; i<=LAST; i++) {
if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
- states.get(i).popFromBackStack(i == LAST);
+ state = states.get(i).popFromBackStack(i == LAST, state);
}
reportBackStackChanged();
}
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 6e99899..7479ecd 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -1,5 +1,8 @@
package android.app;
+import android.util.Pair;
+import android.view.View;
+
/**
* API for performing a set of Fragment operations.
*
@@ -169,6 +172,36 @@
public abstract FragmentTransaction setTransition(int transit);
/**
+ * Set a {@link android.transition.Transition} resource id to use with this transaction.
+ * <var>transitionId</var> will be played for fragments when going forward and when popping
+ * the back stack.
+ * @param sceneRootId The ID of the element acting as the scene root for the transition.
+ * This should be a ViewGroup containing all Fragments in the transaction.
+ * @param transitionId The resource ID for the Transition used during the Fragment transaction.
+ */
+ public abstract FragmentTransaction setCustomTransition(int sceneRootId, int transitionId);
+
+ /**
+ * Used with {@link #setCustomTransition(int, int)} to map a View from a removed or hidden
+ * Fragment to a View from a shown or added Fragment.
+ * <var>sharedElement</var> must have a unique viewName in the View hierarchy.
+ * @param sharedElement A View in a disappearing Fragment to match with a View in an
+ * appearing Fragment.
+ * @param name The viewName for a View in an appearing Fragment to match to the shared
+ * element.
+ */
+ public abstract FragmentTransaction setSharedElement(View sharedElement, String name);
+
+ /**
+ * Used with {@link #setCustomTransition(int, int)} to map multiple Views from removed or hidden
+ * Fragments to a Views from a shown or added Fragments. Views in
+ * <var>sharedElements</var> must have unique viewNames in the View hierarchy.
+ * @param sharedElements Pairs of Views in disappearing Fragments to viewNames in
+ * appearing Fragments.
+ */
+ public abstract FragmentTransaction setSharedElements(Pair<View, String>... sharedElements);
+
+ /**
* Set a custom style resource that will be used for resolving transit
* animations.
*/
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 3ae8bfc..065e88d 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -16,8 +16,8 @@
package android.app;
+import android.text.TextUtils;
import android.util.ArrayMap;
-import com.android.internal.util.ArrayUtils;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -52,6 +52,8 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
final class IntentReceiverLeaked extends AndroidRuntimeException {
@@ -79,6 +81,8 @@
final String mPackageName;
private final String mAppDir;
private final String mResDir;
+ private final String[] mSplitAppDirs;
+ private final String[] mSplitResDirs;
private final String[] mOverlayDirs;
private final String[] mSharedLibraries;
private final String mDataDir;
@@ -116,13 +120,14 @@
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
CompatibilityInfo compatInfo, ClassLoader baseLoader,
boolean securityViolation, boolean includeCode) {
+ final int myUid = Process.myUid();
mActivityThread = activityThread;
mApplicationInfo = aInfo;
mPackageName = aInfo.packageName;
mAppDir = aInfo.sourceDir;
- final int myUid = Process.myUid();
- mResDir = aInfo.uid == myUid ? aInfo.sourceDir
- : aInfo.publicSourceDir;
+ mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
+ mSplitAppDirs = aInfo.splitSourceDirs;
+ mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
mOverlayDirs = aInfo.resourceDirs;
if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
@@ -149,6 +154,8 @@
mPackageName = "android";
mAppDir = null;
mResDir = null;
+ mSplitAppDirs = null;
+ mSplitResDirs = null;
mOverlayDirs = null;
mSharedLibraries = null;
mDataDir = null;
@@ -214,53 +221,6 @@
return ai.sharedLibraryFiles;
}
- /**
- * Combines two arrays (of library names) such that they are
- * concatenated in order but are devoid of duplicates. The
- * result is a single string with the names of the libraries
- * separated by colons, or <code>null</code> if both lists
- * were <code>null</code> or empty.
- *
- * @param list1 null-ok; the first list
- * @param list2 null-ok; the second list
- * @return null-ok; the combination
- */
- private static String combineLibs(String[] list1, String[] list2) {
- StringBuilder result = new StringBuilder(300);
- boolean first = true;
-
- if (list1 != null) {
- for (String s : list1) {
- if (first) {
- first = false;
- } else {
- result.append(':');
- }
- result.append(s);
- }
- }
-
- // Only need to check for duplicates if list1 was non-empty.
- boolean dupCheck = !first;
-
- if (list2 != null) {
- for (String s : list2) {
- if (dupCheck && ArrayUtils.contains(list1, s)) {
- continue;
- }
-
- if (first) {
- first = false;
- } else {
- result.append(':');
- }
- result.append(s);
- }
- }
-
- return result.toString();
- }
-
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader != null) {
@@ -268,8 +228,15 @@
}
if (mIncludeCode && !mPackageName.equals("android")) {
- String zip = mAppDir;
- String libraryPath = mLibDir;
+ final ArrayList<String> zipPaths = new ArrayList<>();
+ final ArrayList<String> libPaths = new ArrayList<>();
+
+ zipPaths.add(mAppDir);
+ if (mSplitAppDirs != null) {
+ Collections.addAll(zipPaths, mSplitAppDirs);
+ }
+
+ libPaths.add(mLibDir);
/*
* The following is a bit of a hack to inject
@@ -280,50 +247,70 @@
* concatenation of both apps' shared library lists.
*/
- String instrumentationAppDir =
- mActivityThread.mInstrumentationAppDir;
- String instrumentationAppLibraryDir =
- mActivityThread.mInstrumentationAppLibraryDir;
- String instrumentationAppPackage =
- mActivityThread.mInstrumentationAppPackage;
- String instrumentedAppDir =
- mActivityThread.mInstrumentedAppDir;
- String instrumentedAppLibraryDir =
- mActivityThread.mInstrumentedAppLibraryDir;
+ String instrumentationPackageName = mActivityThread.mInstrumentationPackageName;
+ String instrumentationAppDir = mActivityThread.mInstrumentationAppDir;
+ String[] instrumentationSplitAppDirs = mActivityThread.mInstrumentationSplitAppDirs;
+ String instrumentationLibDir = mActivityThread.mInstrumentationLibDir;
+
+ String instrumentedAppDir = mActivityThread.mInstrumentedAppDir;
+ String[] instrumentedSplitAppDirs = mActivityThread.mInstrumentedSplitAppDirs;
+ String instrumentedLibDir = mActivityThread.mInstrumentedLibDir;
String[] instrumentationLibs = null;
if (mAppDir.equals(instrumentationAppDir)
|| mAppDir.equals(instrumentedAppDir)) {
- zip = instrumentationAppDir + ":" + instrumentedAppDir;
- libraryPath = instrumentationAppLibraryDir + ":" + instrumentedAppLibraryDir;
- if (! instrumentedAppDir.equals(instrumentationAppDir)) {
- instrumentationLibs =
- getLibrariesFor(instrumentationAppPackage);
+ zipPaths.clear();
+ zipPaths.add(instrumentationAppDir);
+ if (instrumentationSplitAppDirs != null) {
+ Collections.addAll(zipPaths, instrumentationSplitAppDirs);
+ }
+ zipPaths.add(instrumentedAppDir);
+ if (instrumentedSplitAppDirs != null) {
+ Collections.addAll(zipPaths, instrumentedSplitAppDirs);
+ }
+
+ libPaths.clear();
+ libPaths.add(instrumentationLibDir);
+ libPaths.add(instrumentedLibDir);
+
+ if (!instrumentedAppDir.equals(instrumentationAppDir)) {
+ instrumentationLibs = getLibrariesFor(instrumentationPackageName);
}
}
- if ((mSharedLibraries != null) ||
- (instrumentationLibs != null)) {
- zip =
- combineLibs(mSharedLibraries, instrumentationLibs)
- + ':' + zip;
+ if (mSharedLibraries != null) {
+ for (String lib : mSharedLibraries) {
+ if (!zipPaths.contains(lib)) {
+ zipPaths.add(0, lib);
+ }
+ }
}
+ if (instrumentationLibs != null) {
+ for (String lib : instrumentationLibs) {
+ if (!zipPaths.contains(lib)) {
+ zipPaths.add(0, lib);
+ }
+ }
+ }
+
+ final String zip = TextUtils.join(File.pathSeparator, zipPaths);
+ final String lib = TextUtils.join(File.pathSeparator, libPaths);
+
/*
* With all the combination done (if necessary, actually
* create the class loader.
*/
if (ActivityThread.localLOGV)
- Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + libraryPath);
+ Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + lib);
// Temporarily disable logging of disk reads on the Looper thread
// as this is early and necessary.
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- mClassLoader =
- ApplicationLoaders.getDefault().getClassLoader(
- zip, libraryPath, mBaseClassLoader);
+ mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib,
+ mBaseClassLoader);
initializeJavaContextClassLoader();
StrictMode.setThreadPolicy(oldPolicy);
@@ -469,6 +456,14 @@
return mResDir;
}
+ public String[] getSplitAppDirs() {
+ return mSplitAppDirs;
+ }
+
+ public String[] getSplitResDirs() {
+ return mSplitResDirs;
+ }
+
public String[] getOverlayDirs() {
return mOverlayDirs;
}
@@ -487,7 +482,7 @@
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
- mResources = mainThread.getTopLevelResources(mResDir, mOverlayDirs,
+ mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this);
}
return mResources;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 276f936..b94fd41 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2867,16 +2867,16 @@
/**
* Helper class for generating large-format notifications that include a large image attachment.
*
- * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+ * Here's how you'd set the <code>BigPictureStyle</code> on a notification:
* <pre class="prettyprint">
- * Notification noti = new Notification.BigPictureStyle(
- * new Notification.Builder()
- * .setContentTitle("New photo from " + sender.toString())
- * .setContentText(subject)
- * .setSmallIcon(R.drawable.new_post)
- * .setLargeIcon(aBitmap))
- * .bigPicture(aBigBitmap)
- * .build();
+ * Notification notif = new Notification.Builder(mContext)
+ * .setContentTitle("New photo from " + sender.toString())
+ * .setContentText(subject)
+ * .setSmallIcon(R.drawable.new_post)
+ * .setLargeIcon(aBitmap)
+ * .setStyle(new Notification.BigPictureStyle()
+ * .bigPicture(aBigBitmap))
+ * .build();
* </pre>
*
* @see Notification#bigContentView
@@ -2963,16 +2963,16 @@
/**
* Helper class for generating large-format notifications that include a lot of text.
*
- * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+ * Here's how you'd set the <code>BigTextStyle</code> on a notification:
* <pre class="prettyprint">
- * Notification noti = new Notification.BigTextStyle(
- * new Notification.Builder()
- * .setContentTitle("New mail from " + sender.toString())
- * .setContentText(subject)
- * .setSmallIcon(R.drawable.new_mail)
- * .setLargeIcon(aBitmap))
- * .bigText(aVeryLongString)
- * .build();
+ * Notification notif = new Notification.Builder(mContext)
+ * .setContentTitle("New mail from " + sender.toString())
+ * .setContentText(subject)
+ * .setSmallIcon(R.drawable.new_mail)
+ * .setLargeIcon(aBitmap)
+ * .setStyle(new Notification.BigTextStyle()
+ * .bigText(aVeryLongString))
+ * .build();
* </pre>
*
* @see Notification#bigContentView
@@ -3057,19 +3057,19 @@
/**
* Helper class for generating large-format notifications that include a list of (up to 5) strings.
*
- * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+ * Here's how you'd set the <code>InboxStyle</code> on a notification:
* <pre class="prettyprint">
- * Notification noti = new Notification.InboxStyle(
- * new Notification.Builder()
- * .setContentTitle("5 New mails from " + sender.toString())
- * .setContentText(subject)
- * .setSmallIcon(R.drawable.new_mail)
- * .setLargeIcon(aBitmap))
- * .addLine(str1)
- * .addLine(str2)
- * .setContentTitle("")
- * .setSummaryText("+3 more")
- * .build();
+ * Notification notif = new Notification.Builder(mContext)
+ * .setContentTitle("5 New mails from " + sender.toString())
+ * .setContentText(subject)
+ * .setSmallIcon(R.drawable.new_mail)
+ * .setLargeIcon(aBitmap)
+ * .setStyle(new Notification.InboxStyle()
+ * .addLine(str1)
+ * .addLine(str2)
+ * .setContentTitle("")
+ * .setSummaryText("+3 more"))
+ * .build();
* </pre>
*
* @see Notification#bigContentView
@@ -3619,14 +3619,16 @@
* .build();</pre>
*
* <p>The activity to launch needs to allow embedding, must be exported, and
- * should have an empty task affinity.
+ * should have an empty task affinity. It is also recommended to use the device
+ * default light theme.
*
* <p>Example AndroidManifest.xml entry:
* <pre class="prettyprint">
* <activity android:name="com.example.MyDisplayActivity"
* android:exported="true"
* android:allowEmbedded="true"
- * android:taskAffinity="" /></pre>
+ * android:taskAffinity=""
+ * android:theme="@android:style/Theme.DeviceDefault.Light" /></pre>
*
* @param intent the {@link PendingIntent} for an activity
* @return this object for method chaining
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index a67faa0..3c13115 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -149,9 +149,9 @@
* @param compatInfo the compability info. Must not be null.
* @param token the application token for determining stack bounds.
*/
- public Resources getTopLevelResources(String resDir, String[] overlayDirs, String[] libDirs,
- int displayId, Configuration overrideConfiguration, CompatibilityInfo compatInfo,
- IBinder token) {
+ public Resources getTopLevelResources(String resDir, String[] splitResDirs,
+ String[] overlayDirs, String[] libDirs, int displayId,
+ Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
final float scale = compatInfo.applicationScale;
ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale, token);
Resources r;
@@ -182,6 +182,14 @@
return null;
}
+ if (splitResDirs != null) {
+ for (String splitResDir : splitResDirs) {
+ if (assets.addAssetPath(splitResDir) == 0) {
+ return null;
+ }
+ }
+ }
+
if (overlayDirs != null) {
for (String idmapPath : overlayDirs) {
assets.addOverlayPath(idmapPath);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e80c761..ae1a4e7 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -18,6 +18,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -2340,15 +2341,20 @@
}
/**
- * Sets which components may enter lock task mode.
+ * Sets which packages may enter lock task mode.
+ *
+ * <p>Any packages that shares uid with an allowed package will also be allowed
+ * to activate lock task.
*
* This function can only be called by the device owner or the profile owner.
- * @param components The list of components allowed to enter lock task mode
+ * @param packages The list of packages allowed to enter lock task mode
+ *
+ * @see Activity#startLockTask()
*/
- public void setLockTaskComponents(ComponentName[] components) throws SecurityException {
+ public void setLockTaskPackages(String[] packages) throws SecurityException {
if (mService != null) {
try {
- mService.setLockTaskComponents(components);
+ mService.setLockTaskPackages(packages);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2356,13 +2362,13 @@
}
/**
- * This function returns the list of components allowed to start the lock task mode.
+ * This function returns the list of packages allowed to start the lock task mode.
* @hide
*/
- public ComponentName[] getLockTaskComponents() {
+ public String[] getLockTaskPackages() {
if (mService != null) {
try {
- return mService.getLockTaskComponents();
+ return mService.getLockTaskPackages();
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2373,12 +2379,12 @@
/**
* This function lets the caller know whether the given component is allowed to start the
* lock task mode.
- * @param component The component to check
+ * @param pkg The package to check
*/
- public boolean isLockTaskPermitted(ComponentName component) {
+ public boolean isLockTaskPermitted(String pkg) {
if (mService != null) {
try {
- return mService.isLockTaskPermitted(component);
+ return mService.isLockTaskPermitted(pkg);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a1caa21..8272c07 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -142,9 +142,9 @@
void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
String[] getAccountTypesWithManagementDisabled();
- void setLockTaskComponents(in ComponentName[] components);
- ComponentName[] getLockTaskComponents();
- boolean isLockTaskPermitted(in ComponentName component);
+ void setLockTaskPackages(in String[] packages);
+ String[] getLockTaskPackages();
+ boolean isLockTaskPermitted(in String pkg);
void setGlobalSetting(in ComponentName who, in String setting, in String value);
void setSecureSetting(in ComponentName who, in String setting, in String value);
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 56a55fb..706ef04 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -228,19 +228,35 @@
}
/**
- * Get the package name of the next application with data in the backup store.
+ * Get the package name of the next application with data in the backup store, plus
+ * a description of the structure of the restored archive: either TYPE_KEY_VALUE for
+ * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream.
*
- * @return The name of one of the packages supplied to {@link #startRestore},
- * or "" (the empty string) if no more backup data is available,
- * or null if an error occurred (the restore should be aborted and rescheduled).
+ * <p>If the package name in the returned RestoreDescription object is the singleton
+ * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available
+ * in the current restore session: all packages described in startRestore() have been
+ * processed.
+ *
+ * <p>If this method returns {@code null}, it means that a transport-level error has
+ * occurred and the entire restore operation should be abandoned.
+ *
+ * @return A RestoreDescription object containing the name of one of the packages
+ * supplied to {@link #startRestore} plus an indicator of the data type of that
+ * restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that
+ * no more packages can be restored in this session; or {@code null} to indicate
+ * a transport-level error.
*/
- public String nextRestorePackage() {
+ public RestoreDescription nextRestorePackage() {
return null;
}
/**
- * Get the data for the application returned by {@link #nextRestorePackage}.
- * @param data An open, writable file into which the backup data should be stored.
+ * Get the data for the application returned by {@link #nextRestorePackage}, if that
+ * method reported {@link RestoreDescription#TYPE_KEY_VALUE} as its delivery type.
+ * If the package has only TYPE_FULL_STREAM data, then this method will return an
+ * error.
+ *
+ * @param data An open, writable file into which the key/value backup data should be stored.
* @return the same error codes as {@link #startRestore}.
*/
public int getRestoreData(ParcelFileDescriptor outFd) {
@@ -332,32 +348,11 @@
// Full restore interfaces
/**
- * Ask the transport to set up to perform a full data restore of the given packages.
+ * Ask the transport to provide data for the "current" package being restored. This
+ * is the package that was just reported by {@link #nextRestorePackage()} as having
+ * {@link RestoreDescription#TYPE_FULL_STREAM} data.
*
- * @param token A backup token as returned by {@link #getAvailableRestoreSets}
- * or {@link #getCurrentRestoreSet}.
- * @param targetPackage The names of the packages whose data is being requested.
- * @return TRANSPORT_OK to indicate that the OS may proceed with requesting
- * restore data; TRANSPORT_ERROR to indicate a fatal error condition that precludes
- * performing any restore at this time.
- */
- public int prepareFullRestore(long token, String[] targetPackages) {
- return BackupTransport.TRANSPORT_OK;
- }
-
- /**
- * Ask the transport what package's full data will be restored next. When all apps'
- * data has been delivered, the transport should return {@code null} here.
- * @return The package name of the next application whose data will be restored, or
- * {@code null} if all available package has been delivered.
- */
- public String getNextFullRestorePackage() {
- return null;
- }
-
- /**
- * Ask the transport to provide data for the "current" package being restored. The
- * transport then writes some data to the socket supplied to this call, and returns
+ * The transport writes some data to the socket supplied to this call, and returns
* the number of bytes written. The system will then read that many bytes and
* stream them to the application's agent for restore, then will call this method again
* to receive the next chunk of the archive. This sequence will be repeated until the
@@ -369,10 +364,14 @@
* {@link #getNextFullRestorePackage()} to begin the restore process for the next
* application, and the sequence begins again.
*
+ * <p>The transport should always close this socket when returning from this method.
+ * Do not cache this socket across multiple calls or you may leak file descriptors.
+ *
* @param socket The file descriptor that the transport will use for delivering the
- * streamed archive.
+ * streamed archive. The transport must close this socket in all cases when returning
+ * from this method.
* @return 0 when no more data for the current package is available. A positive value
- * indicates the presence of that much data to be delivered to the app. A negative
+ * indicates the presence of that many bytes to be delivered to the app. Any negative
* return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
* indicating a fatal error condition that precludes further restore operations
* on the current dataset.
@@ -380,6 +379,24 @@
public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
return 0;
}
+
+ /**
+ * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
+ * data for restore, it will invoke this method to tell the transport that it should
+ * abandon the data download for the current package. The OS will then either call
+ * {@link #nextRestorePackage()} again to move on to restoring the next package in the
+ * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
+ * operation.
+ *
+ * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
+ * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
+ * transport-level failure. If the transport reports an error here, the entire restore
+ * operation will immediately be finished with no further attempts to restore app data.
+ */
+ public int abortFullRestore() {
+ return BackupTransport.TRANSPORT_OK;
+ }
+
/**
* Bridge between the actual IBackupTransport implementation and the stable API. If the
* binder interface needs to change, we use this layer to translate so that we can
@@ -450,7 +467,7 @@
}
@Override
- public String nextRestorePackage() throws RemoteException {
+ public RestoreDescription nextRestorePackage() throws RemoteException {
return BackupTransport.this.nextRestorePackage();
}
@@ -478,5 +495,15 @@
public int sendBackupData(int numBytes) throws RemoteException {
return BackupTransport.this.sendBackupData(numBytes);
}
+
+ @Override
+ public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
+ return BackupTransport.this.getNextFullRestoreDataChunk(socket);
+ }
+
+ @Override
+ public int abortFullRestore() {
+ return BackupTransport.this.abortFullRestore();
+ }
}
}
diff --git a/core/java/android/app/backup/RestoreDescription.aidl b/core/java/android/app/backup/RestoreDescription.aidl
new file mode 100644
index 0000000..9cbea78
--- /dev/null
+++ b/core/java/android/app/backup/RestoreDescription.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 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.app.backup;
+
+parcelable RestoreDescription;
diff --git a/core/java/android/app/backup/RestoreDescription.java b/core/java/android/app/backup/RestoreDescription.java
new file mode 100644
index 0000000..0fb4355
--- /dev/null
+++ b/core/java/android/app/backup/RestoreDescription.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 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.app.backup;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Description of the available restore data for a given package. Returned by a
+ * BackupTransport in response to a request about the next available restorable
+ * package.
+ *
+ * @see BackupTransport#nextRestorePackage()
+ *
+ * @hide
+ */
+public class RestoreDescription implements Parcelable {
+ private final String mPackageName;
+ private final int mDataType;
+
+ private static final String NO_MORE_PACKAGES_SENTINEL = "";
+
+ /**
+ * Return this constant RestoreDescription from BackupTransport.nextRestorePackage()
+ * to indicate that no more package data is available in the current restore operation.
+ */
+ public static final RestoreDescription NO_MORE_PACKAGES =
+ new RestoreDescription(NO_MORE_PACKAGES_SENTINEL, 0);
+
+ // ---------------------------------------
+ // Data type identifiers
+
+ /** This package's restore data is an original-style key/value dataset */
+ public static final int TYPE_KEY_VALUE = 1;
+
+ /** This package's restore data is a tarball-type full data stream */
+ public static final int TYPE_FULL_STREAM = 2;
+
+ // ---------------------------------------
+ // API
+
+ public RestoreDescription(String packageName, int dataType) {
+ mPackageName = packageName;
+ mDataType = dataType;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public int getDataType() {
+ return mDataType;
+ }
+
+ // ---------------------------------------
+ // Parcelable implementation - not used by transport
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mPackageName);
+ out.writeInt(mDataType);
+ }
+
+ public static final Parcelable.Creator<RestoreDescription> CREATOR
+ = new Parcelable.Creator<RestoreDescription>() {
+ public RestoreDescription createFromParcel(Parcel in) {
+ final RestoreDescription unparceled = new RestoreDescription(in);
+ return (NO_MORE_PACKAGES_SENTINEL.equals(unparceled.mPackageName))
+ ? NO_MORE_PACKAGES
+ : unparceled;
+ }
+
+ public RestoreDescription[] newArray(int size) {
+ return new RestoreDescription[size];
+ }
+ };
+
+ private RestoreDescription(Parcel in) {
+ mPackageName = in.readString();
+ mDataType = in.readInt();
+ }
+}
diff --git a/core/java/android/app/maintenance/IIdleCallback.aidl b/core/java/android/app/maintenance/IIdleCallback.aidl
deleted file mode 100644
index 582dede..0000000
--- a/core/java/android/app/maintenance/IIdleCallback.aidl
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Copyright 2014, 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.app.maintenance;
-
-import android.app.maintenance.IIdleService;
-
-/**
- * The server side of the idle maintenance IPC protocols. The app-side implementation
- * invokes on this interface to indicate completion of the (asynchronous) instructions
- * issued by the server.
- *
- * In all cases, the 'who' parameter is the caller's service binder, used to track
- * which idle service instance is reporting.
- *
- * {@hide}
- */
-interface IIdleCallback {
- /**
- * Acknowledge receipt and processing of the asynchronous "start idle work" incall.
- * 'result' is true if the app wants some time to perform ongoing background
- * idle-time work; or false if the app declares that it does not need any time
- * for such work.
- */
- void acknowledgeStart(int token, boolean result);
-
- /**
- * Acknowledge receipt and processing of the asynchronous "stop idle work" incall.
- */
- void acknowledgeStop(int token);
-
- /*
- * Tell the idle service manager that we're done with our idle maintenance, so that
- * it can go on to the next one and stop attributing wakelock time to us etc.
- *
- * @param opToken The identifier passed in the startIdleMaintenance() call that
- * indicated the beginning of this service's idle timeslice.
- */
- void idleFinished(int token);
-}
diff --git a/core/java/android/app/maintenance/IIdleService.aidl b/core/java/android/app/maintenance/IIdleService.aidl
deleted file mode 100644
index 54abccd..0000000
--- a/core/java/android/app/maintenance/IIdleService.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Copyright 2014, 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.app.maintenance;
-
-import android.app.maintenance.IIdleCallback;
-
-/**
- * Interface that the framework uses to communicate with application code
- * that implements an idle-time "maintenance" service. End user code does
- * not implement this interface directly; instead, the app's idle service
- * implementation will extend android.app.maintenance.IdleService.
- * {@hide}
- */
-oneway interface IIdleService {
- /**
- * Begin your idle-time work.
- */
- void startIdleMaintenance(IIdleCallback callbackBinder, int token);
- void stopIdleMaintenance(IIdleCallback callbackBinder, int token);
-}
diff --git a/core/java/android/app/maintenance/IdleService.java b/core/java/android/app/maintenance/IdleService.java
deleted file mode 100644
index 2331b81..0000000
--- a/core/java/android/app/maintenance/IdleService.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2014 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.app.maintenance;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.Slog;
-
-/**
- * Idle maintenance API. Full docs TBW (to be written).
- */
-public abstract class IdleService extends Service {
- private static final String TAG = "IdleService";
-
- static final int MSG_START = 1;
- static final int MSG_STOP = 2;
- static final int MSG_FINISH = 3;
-
- IdleHandler mHandler;
- IIdleCallback mCallbackBinder;
- int mToken;
- final Object mHandlerLock = new Object();
-
- void ensureHandler() {
- synchronized (mHandlerLock) {
- if (mHandler == null) {
- mHandler = new IdleHandler(getMainLooper());
- }
- }
- }
-
- /**
- * TBW: the idle service should supply an intent-filter handling this intent
- * <p>
- * <p class="note">The application must also protect the idle service with the
- * {@code "android.permission.BIND_IDLE_SERVICE"} permission to ensure that other
- * applications cannot maliciously bind to it. If an idle service's manifest
- * declaration does not require that permission, it will never be invoked.
- * </p>
- */
- @SdkConstant(SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE =
- "android.service.idle.IdleService";
-
- /**
- * Idle services must be protected with this permission:
- *
- * <pre class="prettyprint">
- * <service android:name="MyIdleService"
- * android:permission="android.permission.BIND_IDLE_SERVICE" >
- * ...
- * </service>
- * </pre>
- *
- * <p>If an idle service is declared in the manifest but not protected with this
- * permission, that service will be ignored by the OS.
- */
- public static final String PERMISSION_BIND =
- "android.permission.BIND_IDLE_SERVICE";
-
- // Trampoline: the callbacks are always run on the main thread
- IIdleService mBinder = new IIdleService.Stub() {
- @Override
- public void startIdleMaintenance(IIdleCallback callbackBinder, int token)
- throws RemoteException {
- ensureHandler();
- Message msg = mHandler.obtainMessage(MSG_START, token, 0, callbackBinder);
- mHandler.sendMessage(msg);
- }
-
- @Override
- public void stopIdleMaintenance(IIdleCallback callbackBinder, int token)
- throws RemoteException {
- ensureHandler();
- Message msg = mHandler.obtainMessage(MSG_STOP, token, 0, callbackBinder);
- mHandler.sendMessage(msg);
- }
- };
-
- /**
- * Your application may begin doing "idle" maintenance work in the background.
- * <p>
- * Your application may continue to run in the background until it receives a call
- * to {@link #onIdleStop()}, at which point you <i>must</i> cease doing work. The
- * OS will hold a wakelock on your application's behalf from the time this method is
- * called until after the following call to {@link #onIdleStop()} returns.
- * </p>
- * <p>
- * Returning {@code false} from this method indicates that you have no ongoing work
- * to do at present. The OS will respond by immediately calling {@link #onIdleStop()}
- * and returning your application to its normal stopped state. Returning {@code true}
- * indicates that the application is indeed performing ongoing work, so the OS will
- * let your application run in this state until it's no longer appropriate.
- * </p>
- * <p>
- * You will always receive a matching call to {@link #onIdleStop()} even if your
- * application returns {@code false} from this method.
- *
- * @return {@code true} to indicate that the application wishes to perform some ongoing
- * background work; {@code false} to indicate that it does not need to perform such
- * work at present.
- */
- public abstract boolean onIdleStart();
-
- /**
- * Your app's maintenance opportunity is over. Once the application returns from
- * this method, the wakelock held by the OS on its behalf will be released.
- */
- public abstract void onIdleStop();
-
- /**
- * Tell the OS that you have finished your idle work. Calling this more than once,
- * or calling it when you have not received an {@link #onIdleStart()} callback, is
- * an error.
- *
- * <p>It is safe to call {@link #finishIdle()} from any thread.
- */
- public final void finishIdle() {
- ensureHandler();
- mHandler.sendEmptyMessage(MSG_FINISH);
- }
-
- class IdleHandler extends Handler {
- IdleHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_START: {
- // Call the concrete onIdleStart(), reporting its return value back to
- // the OS. If onIdleStart() throws, report it as a 'false' return but
- // rethrow the exception at the offending app.
- boolean result = false;
- IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
- mCallbackBinder = callbackBinder;
- final int token = mToken = msg.arg1;
- try {
- result = IdleService.this.onIdleStart();
- } catch (Exception e) {
- Log.e(TAG, "Unable to start idle workload", e);
- throw new RuntimeException(e);
- } finally {
- // don't bother if the service already called finishIdle()
- if (mCallbackBinder != null) {
- try {
- callbackBinder.acknowledgeStart(token, result);
- } catch (RemoteException re) {
- Log.e(TAG, "System unreachable to start idle workload");
- }
- }
- }
- break;
- }
-
- case MSG_STOP: {
- // Structured just like MSG_START for the stop-idle bookend call.
- IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
- final int token = msg.arg1;
- try {
- IdleService.this.onIdleStop();
- } catch (Exception e) {
- Log.e(TAG, "Unable to stop idle workload", e);
- throw new RuntimeException(e);
- } finally {
- if (mCallbackBinder != null) {
- try {
- callbackBinder.acknowledgeStop(token);
- } catch (RemoteException re) {
- Log.e(TAG, "System unreachable to stop idle workload");
- }
- }
- }
- break;
- }
-
- case MSG_FINISH: {
- if (mCallbackBinder != null) {
- try {
- mCallbackBinder.idleFinished(mToken);
- } catch (RemoteException e) {
- Log.e(TAG, "System unreachable to finish idling");
- } finally {
- mCallbackBinder = null;
- }
- } else {
- Log.e(TAG, "finishIdle() called but the idle service is not started");
- }
- break;
- }
-
- default: {
- Slog.w(TAG, "Unknown message " + msg.what);
- }
- }
- }
- }
-
- /** @hide */
- @Override
- public final IBinder onBind(Intent intent) {
- return mBinder.asBinder();
- }
-
-}
diff --git a/core/java/android/app/maintenance/package.html b/core/java/android/app/maintenance/package.html
deleted file mode 100644
index 1c9bf9d..0000000
--- a/core/java/android/app/maintenance/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-<body>
- {@hide}
-</body>
-</html>
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6e53a6fb..3dfa78b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -7375,6 +7375,7 @@
for (int categoryNdx = mCategories.size() - 1; categoryNdx >= 0; --categoryNdx) {
out.attribute(null, ATTR_CATEGORY, mCategories.valueAt(categoryNdx));
}
+ out.endTag(null, TAG_CATEGORIES);
}
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 791e5aa..abc8cde 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -104,6 +104,28 @@
public int documentLaunchMode;
/**
+ * Constant corresponding to <code>persistRootOnly</code> in
+ * the {@link android.R.attr#persistableMode} attribute.
+ */
+ public static final int PERSIST_ROOT_ONLY = 0;
+ /**
+ * Constant corresponding to <code>doNotPersist</code> in
+ * the {@link android.R.attr#persistableMode} attribute.
+ */
+ public static final int DO_NOT_PERSIST = 1;
+ /**
+ * Constant corresponding to <code>persistAcrossReboots</code> in
+ * the {@link android.R.attr#persistableMode} attribute.
+ */
+ public static final int PERSIST_ACROSS_REBOOTS = 2;
+ /**
+ * Value indicating how this activity is to be persisted across
+ * reboots for restoring in the Recents list.
+ * {@link android.R.attr#persistableMode}
+ */
+ public int persistableMode;
+
+ /**
* The maximum number of tasks rooted at this activity that can be in the recent task list.
* Refer to {@link android.R.attr#maxRecents}.
*/
@@ -230,12 +252,6 @@
*/
public static final int FLAG_IMMERSIVE = 0x0800;
/**
- * Bit in {@link #flags} indicating that this activity is to be persisted across
- * reboots for display in the Recents list.
- * {@link android.R.attr#persistable}
- */
- public static final int FLAG_PERSISTABLE = 0x1000;
- /**
* Bit in {@link #flags} indicating that tasks started with this activity are to be
* removed from the recent list of tasks when the last activity in the task is finished.
* {@link android.R.attr#autoRemoveFromRecents}
@@ -641,13 +657,23 @@
return theme != 0 ? theme : applicationInfo.theme;
}
+ private String persistableModeToString() {
+ switch(persistableMode) {
+ case PERSIST_ROOT_ONLY: return "PERSIST_ROOT_ONLY";
+ case DO_NOT_PERSIST: return "DO_NOT_PERSIST";
+ case PERSIST_ACROSS_REBOOTS: return "PERSIST_ACROSS_REBOOTS";
+ default: return "UNKNOWN=" + persistableMode;
+ }
+ }
+
public void dump(Printer pw, String prefix) {
super.dumpFront(pw, prefix);
if (permission != null) {
pw.println(prefix + "permission=" + permission);
}
pw.println(prefix + "taskAffinity=" + taskAffinity
- + " targetActivity=" + targetActivity);
+ + " targetActivity=" + targetActivity
+ + " persistableMode=" + persistableModeToString());
if (launchMode != 0 || flags != 0 || theme != 0) {
pw.println(prefix + "launchMode=" + launchMode
+ " flags=0x" + Integer.toHexString(flags)
@@ -688,6 +714,7 @@
dest.writeInt(softInputMode);
dest.writeInt(uiOptions);
dest.writeString(parentActivityName);
+ dest.writeInt(persistableMode);
}
public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -713,5 +740,6 @@
softInputMode = source.readInt();
uiOptions = source.readInt();
parentActivityName = source.readString();
+ persistableMode = source.readInt();
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6b44a11..06f4019 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -23,8 +23,12 @@
import android.os.Parcelable;
import android.util.Printer;
+import com.android.internal.util.ArrayUtils;
+
import java.text.Collator;
+import java.util.Arrays;
import java.util.Comparator;
+import java.util.Objects;
/**
* Information you can retrieve about a particular application. This
@@ -398,17 +402,30 @@
public int largestWidthLimitDp = 0;
/**
- * Full path to the location of this package.
+ * Full path to the base APK for this application.
*/
public String sourceDir;
/**
- * Full path to the location of the publicly available parts of this
- * package (i.e. the primary resource package and manifest). For
- * non-forward-locked apps this will be the same as {@link #sourceDir).
+ * Full path to the publicly available parts of {@link #sourceDir},
+ * including resources and manifest. This may be different from
+ * {@link #sourceDir} if an application is forward locked.
*/
public String publicSourceDir;
-
+
+ /**
+ * Full paths to zero or more split APKs that, when combined with the base
+ * APK defined in {@link #sourceDir}, form a complete application.
+ */
+ public String[] splitSourceDirs;
+
+ /**
+ * Full path to the publicly available parts of {@link #splitSourceDirs},
+ * including resources and manifest. This may be different from
+ * {@link #splitSourceDirs} if an application is forward locked.
+ */
+ public String[] splitPublicSourceDirs;
+
/**
* Full paths to the locations of extra resource packages this application
* uses. This field is only used if there are extra resource packages,
@@ -512,13 +529,16 @@
+ " compatibleWidthLimitDp=" + compatibleWidthLimitDp
+ " largestWidthLimitDp=" + largestWidthLimitDp);
pw.println(prefix + "sourceDir=" + sourceDir);
- if (sourceDir == null) {
- if (publicSourceDir != null) {
- pw.println(prefix + "publicSourceDir=" + publicSourceDir);
- }
- } else if (!sourceDir.equals(publicSourceDir)) {
+ if (!Objects.equals(sourceDir, publicSourceDir)) {
pw.println(prefix + "publicSourceDir=" + publicSourceDir);
}
+ if (!ArrayUtils.isEmpty(splitSourceDirs)) {
+ pw.println(prefix + "splitSourceDirs=" + Arrays.toString(splitSourceDirs));
+ }
+ if (!ArrayUtils.isEmpty(splitPublicSourceDirs)
+ && !Arrays.equals(splitSourceDirs, splitPublicSourceDirs)) {
+ pw.println(prefix + "splitPublicSourceDirs=" + Arrays.toString(splitPublicSourceDirs));
+ }
if (resourceDirs != null) {
pw.println(prefix + "resourceDirs=" + resourceDirs);
}
@@ -591,6 +611,8 @@
largestWidthLimitDp = orig.largestWidthLimitDp;
sourceDir = orig.sourceDir;
publicSourceDir = orig.publicSourceDir;
+ splitSourceDirs = orig.splitSourceDirs;
+ splitPublicSourceDirs = orig.splitPublicSourceDirs;
nativeLibraryDir = orig.nativeLibraryDir;
cpuAbi = orig.cpuAbi;
resourceDirs = orig.resourceDirs;
@@ -633,6 +655,8 @@
dest.writeInt(largestWidthLimitDp);
dest.writeString(sourceDir);
dest.writeString(publicSourceDir);
+ dest.writeStringArray(splitSourceDirs);
+ dest.writeStringArray(splitPublicSourceDirs);
dest.writeString(nativeLibraryDir);
dest.writeString(cpuAbi);
dest.writeStringArray(resourceDirs);
@@ -674,6 +698,8 @@
largestWidthLimitDp = source.readInt();
sourceDir = source.readString();
publicSourceDir = source.readString();
+ splitSourceDirs = source.readStringArray();
+ splitPublicSourceDirs = source.readStringArray();
nativeLibraryDir = source.readString();
cpuAbi = source.readString();
resourceDirs = source.readStringArray();
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index a977e41..dab0caf 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -30,17 +30,32 @@
* "package" attribute.
*/
public String targetPackage;
-
+
/**
- * Full path to the location of this package.
+ * Full path to the base APK for this application.
*/
public String sourceDir;
-
+
/**
- * Full path to the location of the publicly available parts of this package (i.e. the resources
- * and manifest). For non-forward-locked apps this will be the same as {@link #sourceDir).
+ * Full path to the publicly available parts of {@link #sourceDir},
+ * including resources and manifest. This may be different from
+ * {@link #sourceDir} if an application is forward locked.
*/
public String publicSourceDir;
+
+ /**
+ * Full paths to zero or more split APKs that, when combined with the base
+ * APK defined in {@link #sourceDir}, form a complete application.
+ */
+ public String[] splitSourceDirs;
+
+ /**
+ * Full path to the publicly available parts of {@link #splitSourceDirs},
+ * including resources and manifest. This may be different from
+ * {@link #splitSourceDirs} if an application is forward locked.
+ */
+ public String[] splitPublicSourceDirs;
+
/**
* Full path to a directory assigned to the package for its persistent
* data.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 91895ff..618c2bd6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2607,10 +2607,9 @@
com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
0);
- if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
- a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
- }
+ a.info.persistableMode = sa.getInteger(
+ com.android.internal.R.styleable.AndroidManifestActivity_persistableMode,
+ ActivityInfo.PERSIST_ROOT_ONLY);
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index 4c50dda..31896f5 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -69,4 +69,9 @@
* well-formatted in the generated java method.
*/
int getCameraVendorTagDescriptor(out BinderHolder desc);
+
+ // Writes the camera1 parameters into a single-element array.
+ int getLegacyParameters(int cameraId, out String[] parameters);
+ // Determines if a particular API version is supported; see ICameraService.h for version defines
+ int supportsCameraApi(int cameraId, int apiVersion);
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 0901562..73188ff 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -19,8 +19,10 @@
import android.content.Context;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
+import android.hardware.CameraInfo;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.legacy.CameraDeviceUserShim;
+import android.hardware.camera2.legacy.LegacyMetadataMapper;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.hardware.camera2.utils.BinderHolder;
@@ -57,6 +59,10 @@
private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
private static final int USE_CALLING_UID = -1;
+ @SuppressWarnings("unused")
+ private static final int API_VERSION_1 = 1;
+ private static final int API_VERSION_2 = 2;
+
private final ICameraService mCameraService;
private ArrayList<String> mDeviceIdList;
@@ -142,6 +148,9 @@
synchronized (mLock) {
mListenerMap.put(listener, handler);
+
+ // TODO: fire the current oldest known state when adding a new listener
+ // (must be done while holding lock)
}
}
@@ -185,16 +194,46 @@
}
}
- CameraMetadataNative info = new CameraMetadataNative();
- try {
- mCameraService.getCameraCharacteristics(Integer.valueOf(cameraId), info);
- } catch(CameraRuntimeException e) {
- throw e.asChecked();
- } catch(RemoteException e) {
- // impossible
- return null;
+ int id = Integer.valueOf(cameraId);
+
+ /*
+ * Get the camera characteristics from the camera service directly if it supports it,
+ * otherwise get them from the legacy shim instead.
+ */
+
+ if (!supportsCamera2Api(cameraId)) {
+ // Legacy backwards compatibility path; build static info from the camera parameters
+ String[] outParameters = new String[1];
+ try {
+ mCameraService.getLegacyParameters(id, /*out*/outParameters);
+ String parameters = outParameters[0];
+
+ CameraInfo info = new CameraInfo();
+ mCameraService.getCameraInfo(id, /*out*/info);
+
+ return LegacyMetadataMapper.createCharacteristics(parameters, info);
+ } catch (RemoteException e) {
+ // Impossible
+ return null;
+ } catch (CameraRuntimeException e) {
+ throw e.asChecked();
+ }
+
+ } else {
+ // Normal path: Get the camera characteristics directly from the camera service
+ CameraMetadataNative info = new CameraMetadataNative();
+
+ try {
+ mCameraService.getCameraCharacteristics(id, info);
+ } catch(CameraRuntimeException e) {
+ throw e.asChecked();
+ } catch(RemoteException e) {
+ // impossible
+ return null;
+ }
+
+ return new CameraCharacteristics(info);
}
- return new CameraCharacteristics(info);
}
/**
@@ -456,6 +495,53 @@
}
}
+ /**
+ * Queries the camera service if it supports the camera2 api directly, or needs a shim.
+ *
+ * @param cameraId a non-{@code null} camera identifier
+ * @return {@code false} if the legacy shim needs to be used, {@code true} otherwise.
+ */
+ private boolean supportsCamera2Api(String cameraId) {
+ return supportsCameraApi(cameraId, API_VERSION_2);
+ }
+
+ /**
+ * Queries the camera service if it supports a camera api directly, or needs a shim.
+ *
+ * @param cameraId a non-{@code null} camera identifier
+ * @param apiVersion the version, i.e. {@code API_VERSION_1} or {@code API_VERSION_2}
+ * @return {@code true} if connecting will work for that device version.
+ */
+ private boolean supportsCameraApi(String cameraId, int apiVersion) {
+ int id = Integer.parseInt(cameraId);
+
+ /*
+ * Possible return values:
+ * - NO_ERROR => Camera2 API is supported
+ * - CAMERA_DEPRECATED_HAL => Camera2 API is *not* supported (thrown as an exception)
+ *
+ * Anything else is an unexpected error we don't want to recover from.
+ */
+
+ try {
+ int res = mCameraService.supportsCameraApi(id, apiVersion);
+
+ if (res != CameraBinderDecorator.NO_ERROR) {
+ throw new AssertionError("Unexpected value " + res);
+ }
+
+ return true;
+ } catch (CameraRuntimeException e) {
+ if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
+ return false;
+ } else {
+ throw e;
+ }
+ } catch (RemoteException e) {
+ throw new AssertionError("Camera service unreachable", e);
+ }
+ }
+
// TODO: this class needs unit tests
// TODO: extract class into top level
private class CameraServiceListener extends ICameraServiceListener.Stub {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index 22ff9c6..ab7e844 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -34,6 +34,7 @@
* <li>{@code CONFIGURING -> IDLE}</li>
* <li>{@code IDLE -> CONFIGURING}</li>
* <li>{@code IDLE -> CAPTURING}</li>
+ * <li>{@code IDLE -> IDLE}</li>
* <li>{@code CAPTURING -> IDLE}</li>
* <li>{@code ANY -> ERROR}</li>
* </ul>
@@ -216,12 +217,17 @@
mCurrentState = STATE_CONFIGURING;
break;
case STATE_IDLE:
+ if (mCurrentState == STATE_IDLE) {
+ break;
+ }
+
if (mCurrentState != STATE_CONFIGURING && mCurrentState != STATE_CAPTURING) {
Log.e(TAG, "Cannot call idle while in state: " + mCurrentState);
mCurrentError = CameraBinderDecorator.INVALID_OPERATION;
doStateTransition(STATE_ERROR);
break;
}
+
if (mCurrentState != STATE_IDLE && mCurrentHandler != null &&
mCurrentListener != null) {
mCurrentHandler.post(new Runnable() {
diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
index 3fd2309..0382557 100644
--- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
@@ -148,6 +148,12 @@
Handler handler = mGLHandlerThread.getHandler();
handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
mGLHandlerThread.quitSafely();
+ try {
+ mGLHandlerThread.join();
+ } catch (InterruptedException e) {
+ Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
+ mGLHandlerThread.getName(), mGLHandlerThread.getId()));
+ }
}
/**
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index f9cf905..c34a34d 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -48,7 +48,6 @@
*/
public class LegacyCameraDevice implements AutoCloseable {
public static final String DEBUG_PROP = "HAL1ShimLogging";
-
private final String TAG;
private final int mCameraId;
@@ -56,10 +55,11 @@
private final CameraDeviceState mDeviceState = new CameraDeviceState();
private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
- private final AtomicInteger mRequestIdCounter = new AtomicInteger(0);
- private final HandlerThread mCallbackHandlerThread = new HandlerThread("ResultThread");
+ private final HandlerThread mResultThread = new HandlerThread("ResultThread");
+ private final HandlerThread mCallbackHandlerThread = new HandlerThread("CallbackThread");
private final Handler mCallbackHandler;
+ private final Handler mResultHandler;
private static final int ILLEGAL_VALUE = -1;
private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
@@ -81,11 +81,18 @@
public void onError(final int errorCode, RequestHolder holder) {
mIdle.open();
final CaptureResultExtras extras = getExtrasFromRequest(holder);
- try {
- mDeviceCallbacks.onCameraError(errorCode, extras);
- } catch (RemoteException e) {
- Log.e(TAG, "Received remote exception during onCameraError callback: ", e);
- }
+ mResultHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mDeviceCallbacks.onCameraError(errorCode, extras);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Received remote exception during onCameraError callback: ", e);
+ }
+ }
+ });
+
}
@@ -98,36 +105,55 @@
public void onIdle() {
mIdle.open();
- try {
- mDeviceCallbacks.onCameraIdle();
- } catch (RemoteException e) {
- Log.e(TAG, "Received remote exception during onCameraIdle callback: ", e);
- }
+ mResultHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mDeviceCallbacks.onCameraIdle();
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Received remote exception during onCameraIdle callback: ", e);
+ }
+ }
+ });
}
@Override
public void onCaptureStarted(RequestHolder holder) {
final CaptureResultExtras extras = getExtrasFromRequest(holder);
- try {
- // TODO: Don't fake timestamp
- mDeviceCallbacks.onCaptureStarted(extras, System.nanoTime());
- } catch (RemoteException e) {
- Log.e(TAG, "Received remote exception during onCameraError callback: ", e);
- }
+ final long timestamp = System.nanoTime();
+ mResultHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // TODO: Don't fake timestamp
+ mDeviceCallbacks.onCaptureStarted(extras, timestamp);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Received remote exception during onCameraError callback: ", e);
+ }
+ }
+ });
}
@Override
- public void onCaptureResult(CameraMetadataNative result, RequestHolder holder) {
+ public void onCaptureResult(final CameraMetadataNative result, RequestHolder holder) {
final CaptureResultExtras extras = getExtrasFromRequest(holder);
- try {
- // TODO: Don't fake metadata
- mDeviceCallbacks.onResultReceived(result, extras);
- } catch (RemoteException e) {
- Log.e(TAG, "Received remote exception during onCameraError callback: ", e);
- }
+ mResultHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // TODO: Don't fake metadata
+ mDeviceCallbacks.onResultReceived(result, extras);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Received remote exception during onCameraError callback: ", e);
+ }
+ }
+ });
}
};
@@ -161,6 +187,8 @@
mDeviceCallbacks = callbacks;
TAG = String.format("CameraDevice-%d-LE", mCameraId);
+ mResultThread.start();
+ mResultHandler = new Handler(mResultThread.getLooper());
mCallbackHandlerThread.start();
mCallbackHandler = new Handler(mCallbackHandlerThread.getLooper());
mDeviceState.setCameraDeviceCallbacks(mCallbackHandler, mStateListener);
@@ -244,6 +272,22 @@
public void close() {
mRequestThreadManager.quit();
mCallbackHandlerThread.quitSafely();
+ mResultThread.quitSafely();
+
+ try {
+ mCallbackHandlerThread.join();
+ } catch (InterruptedException e) {
+ Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
+ mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId()));
+ }
+
+ try {
+ mResultThread.join();
+ } catch (InterruptedException e) {
+ Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
+ mResultThread.getName(), mResultThread.getId()));
+ }
+
// TODO: throw IllegalStateException in every method after close has been called
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
new file mode 100644
index 0000000..8bb066f
--- /dev/null
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014 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.hardware.camera2.legacy;
+
+import android.graphics.ImageFormat;
+import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
+import android.hardware.Camera.Size;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.StreamConfiguration;
+import android.hardware.camera2.params.StreamConfigurationDuration;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.CameraCharacteristics.*;
+
+/**
+ * Provide legacy-specific implementations of camera2 metadata for legacy devices, such as the
+ * camera characteristics.
+ */
+public class LegacyMetadataMapper {
+ private static final String TAG = "LegacyMetadataMapper";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ // from graphics.h
+ private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
+ private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
+
+ /**
+ * Create characteristics for a legacy device by mapping the {@code parameters}
+ * and {@code info}
+ *
+ * @param parameters A string parseable by {@link Camera.Parameters#unflatten}
+ * @param info Camera info with camera facing direction and angle of orientation
+ * @return static camera characteristics for a camera device
+ *
+ * @throws NullPointerException if any of the args were {@code null}
+ */
+ public static CameraCharacteristics createCharacteristics(String parameters,
+ android.hardware.CameraInfo info) {
+ checkNotNull(parameters, "parameters must not be null");
+ checkNotNull(info, "info must not be null");
+ checkNotNull(info.info, "info.info must not be null");
+
+ CameraMetadataNative m = new CameraMetadataNative();
+
+ mapCameraInfo(m, info.info);
+
+ Camera.Parameters params = Camera.getEmptyParameters();
+ params.unflatten(parameters);
+ mapCameraParameters(m, params);
+
+ if (VERBOSE) {
+ Log.v(TAG, "createCharacteristics metadata:");
+ Log.v(TAG, "--------------------------------------------------- (start)");
+ m.dumpToLog();
+ Log.v(TAG, "--------------------------------------------------- (end)");
+ }
+
+ return new CameraCharacteristics(m);
+ }
+
+ private static void mapCameraInfo(CameraMetadataNative m, CameraInfo i) {
+ m.set(LENS_FACING, i.facing == CameraInfo.CAMERA_FACING_BACK ?
+ LENS_FACING_BACK : LENS_FACING_FRONT);
+ m.set(SENSOR_ORIENTATION, i.orientation);
+ }
+
+ private static void mapCameraParameters(CameraMetadataNative m, Camera.Parameters p) {
+ mapStreamConfigs(m, p);
+
+ // TODO: map other fields
+ }
+
+ private static void mapStreamConfigs(CameraMetadataNative m, Camera.Parameters p) {
+ // TODO: set non-empty durations
+ m.set(SCALER_AVAILABLE_MIN_FRAME_DURATIONS, new StreamConfigurationDuration[] {} );
+ m.set(SCALER_AVAILABLE_STALL_DURATIONS, new StreamConfigurationDuration[] {} );
+
+ ArrayList<StreamConfiguration> availableStreamConfigs = new ArrayList<>();
+ /*
+ * Implementation-defined (preview, recording, etc) -> use camera1 preview sizes
+ * YUV_420_888 cpu callbacks -> use camera1 preview sizes
+ * Other preview callbacks (CPU) -> use camera1 preview sizes
+ * JPEG still capture -> use camera1 still capture sizes
+ *
+ * Use platform-internal format constants here, since StreamConfigurationMap does the
+ * remapping to public format constants.
+ */
+ List<Size> previewSizes = p.getSupportedPreviewSizes();
+ appendStreamConfig(availableStreamConfigs,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, previewSizes);
+ appendStreamConfig(availableStreamConfigs,
+ ImageFormat.YUV_420_888, previewSizes);
+ for (int format : p.getSupportedPreviewFormats()) {
+ if (ImageFormat.isPublicFormat(format)) {
+ appendStreamConfig(availableStreamConfigs, format, previewSizes);
+ } else {
+ /*
+ * Do not add any formats unknown to us
+ * (since it would fail runtime checks in StreamConfigurationMap)
+ */
+ Log.w(TAG,
+ String.format("mapStreamConfigs - Skipping non-public format %x", format));
+ }
+ }
+ appendStreamConfig(availableStreamConfigs,
+ HAL_PIXEL_FORMAT_BLOB, p.getSupportedPictureSizes());
+ m.set(SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ availableStreamConfigs.toArray(new StreamConfiguration[0]));
+ }
+
+ private static void appendStreamConfig(
+ ArrayList<StreamConfiguration> configs, int format, List<Camera.Size> sizes) {
+ for (Camera.Size size : sizes) {
+ StreamConfiguration config =
+ new StreamConfiguration(format, size.width, size.height, /*input*/false);
+ configs.add(config);
+ }
+ }
+}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index c4669f5..7b522ff 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -20,6 +20,7 @@
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.utils.LongParcelable;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.os.ConditionVariable;
@@ -28,12 +29,15 @@
import android.os.SystemClock;
import android.util.Log;
import android.util.Pair;
+import android.util.Size;
import android.view.Surface;
import java.io.IOError;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
@@ -64,6 +68,7 @@
private static final int PREVIEW_FRAME_TIMEOUT = 300; // ms
private static final int JPEG_FRAME_TIMEOUT = 1000; // ms
+ private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
private boolean mPreviewRunning = false;
private volatile RequestHolder mInFlightPreview;
@@ -74,6 +79,8 @@
private GLThreadManager mGLThreadManager;
private SurfaceTexture mPreviewTexture;
+ private Size mIntermediateBufferSize;
+
private final RequestQueue mRequestQueue = new RequestQueue();
private SurfaceTexture mDummyTexture;
private Surface mDummySurface;
@@ -93,6 +100,31 @@
}
}
+
+ /**
+ * Comparator for {@link Size} objects.
+ *
+ * <p>This comparator compares by rectangle area. Tiebreaks on width.</p>
+ */
+ private static class SizeComparator implements Comparator<Size> {
+ @Override
+ public int compare(Size size, Size size2) {
+ if (size == null || size2 == null) {
+ throw new NullPointerException("Null argument passed to compare");
+ }
+ if (size.equals(size2)) return 0;
+ long width = size.getWidth();
+ long width2 = size2.getWidth();
+ long area = width * size.getHeight();
+ long area2 = width2 * size2.getHeight();
+ if (area == area2) {
+ return (width > width2) ? 1 : -1;
+ }
+ return (area > area2) ? 1 : -1;
+
+ }
+ }
+
/**
* Counter class used to calculate and log the current FPS of frame production.
*/
@@ -230,7 +262,13 @@
return; // Already running
}
- mPreviewTexture.setDefaultBufferSize(640, 480); // TODO: size selection based on request
+ if (mPreviewTexture == null) {
+ throw new IllegalStateException(
+ "Preview capture called with no preview surfaces configured.");
+ }
+
+ mPreviewTexture.setDefaultBufferSize(mIntermediateBufferSize.getWidth(),
+ mIntermediateBufferSize.getHeight());
mCamera.setPreviewTexture(mPreviewTexture);
Camera.Parameters params = mCamera.getParameters();
List<int[]> supportedFpsRanges = params.getSupportedPreviewFpsRange();
@@ -248,6 +286,7 @@
startPreview();
}
+
private void configureOutputs(Collection<Surface> outputs) throws IOException {
stopPreview();
if (mGLThreadManager != null) {
@@ -261,6 +300,7 @@
mInFlightPreview = null;
mInFlightJpeg = null;
+
for (Surface s : outputs) {
int format = LegacyCameraDevice.nativeDetectSurfaceType(s);
switch (format) {
@@ -273,6 +313,52 @@
}
}
+ if (mPreviewOutputs.size() > 0) {
+ List<Size> outputSizes = new ArrayList<>(outputs.size());
+ for (Surface s : mPreviewOutputs) {
+ int[] dimens = {0, 0};
+ LegacyCameraDevice.nativeDetectSurfaceDimens(s, dimens);
+ outputSizes.add(new Size(dimens[0], dimens[1]));
+ }
+
+ Size largestOutput = findLargestByArea(outputSizes);
+
+ Camera.Parameters params = mCamera.getParameters();
+
+ // Find largest jpeg dimension - assume to have the same aspect ratio as sensor.
+ List<Size> supportedJpegSizes = convertSizeList(params.getSupportedPictureSizes());
+ Size largestJpegDimen = findLargestByArea(supportedJpegSizes);
+
+ List<Size> supportedPreviewSizes = convertSizeList(params.getSupportedPreviewSizes());
+
+ // Use smallest preview dimension with same aspect ratio as sensor that is >= than all
+ // of the configured output dimensions. If none exists, fall back to using the largest
+ // supported preview size.
+ long largestOutputArea = largestOutput.getHeight() * (long) largestOutput.getWidth();
+ Size bestPreviewDimen = findLargestByArea(supportedPreviewSizes);
+ for (Size s : supportedPreviewSizes) {
+ long currArea = s.getWidth() * s.getHeight();
+ long bestArea = bestPreviewDimen.getWidth() * bestPreviewDimen.getHeight();
+ if (checkAspectRatiosMatch(largestJpegDimen, s) && (currArea < bestArea &&
+ currArea >= largestOutputArea)) {
+ bestPreviewDimen = s;
+ }
+ }
+
+ mIntermediateBufferSize = bestPreviewDimen;
+ if (DEBUG) {
+ Log.d(TAG, "Intermediate buffer selected with dimens: " +
+ bestPreviewDimen.toString());
+ }
+ } else {
+ mIntermediateBufferSize = null;
+ if (DEBUG) {
+ Log.d(TAG, "No Intermediate buffer selected, no preview outputs were configured");
+ }
+ }
+
+
+
// TODO: Detect and optimize single-output paths here to skip stream teeing.
if (mGLThreadManager == null) {
mGLThreadManager = new GLThreadManager(mCameraId);
@@ -282,7 +368,28 @@
mGLThreadManager.setConfigurationAndWait(mPreviewOutputs);
mGLThreadManager.allowNewFrames();
mPreviewTexture = mGLThreadManager.getCurrentSurfaceTexture();
- mPreviewTexture.setOnFrameAvailableListener(mPreviewCallback);
+ if (mPreviewTexture != null) {
+ mPreviewTexture.setOnFrameAvailableListener(mPreviewCallback);
+ }
+ }
+
+ private static Size findLargestByArea(List<Size> sizes) {
+ return Collections.max(sizes, new SizeComparator());
+ }
+
+ private static boolean checkAspectRatiosMatch(Size a, Size b) {
+ float aAspect = a.getWidth() / (float) a.getHeight();
+ float bAspect = b.getWidth() / (float) b.getHeight();
+
+ return Math.abs(aAspect - bAspect) < ASPECT_RATIO_TOLERANCE;
+ }
+
+ private static List<Size> convertSizeList(List<Camera.Size> sizeList) {
+ List<Size> sizes = new ArrayList<>(sizeList.size());
+ for (Camera.Size s : sizeList) {
+ sizes.add(new Size(s.width, s.height));
+ }
+ return sizes;
}
// Calculate the highest FPS range supported
@@ -376,8 +483,10 @@
// TODO: err handling
throw new IOError(e);
}
- // TODO: Set fields in result.
- mDeviceState.setCaptureResult(holder, new CameraMetadataNative());
+ Camera.Parameters params = mCamera.getParameters();
+ CameraMetadataNative result = convertResultMetadata(params,
+ holder.getRequest());
+ mDeviceState.setCaptureResult(holder, result);
}
break;
case MSG_CLEANUP:
@@ -397,6 +506,15 @@
}
};
+ private CameraMetadataNative convertResultMetadata(Camera.Parameters params,
+ CaptureRequest request) {
+ CameraMetadataNative result = new CameraMetadataNative();
+ result.set(CaptureResult.LENS_FOCAL_LENGTH, params.getFocalLength());
+
+ // TODO: Remaining result metadata tags conversions.
+ return result;
+ }
+
/**
* Create a new RequestThreadManager.
*
@@ -437,6 +555,12 @@
Handler handler = mRequestThread.waitAndGetHandler();
handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
mRequestThread.quitSafely();
+ try {
+ mRequestThread.join();
+ } catch (InterruptedException e) {
+ Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
+ mRequestThread.getName(), mRequestThread.getId()));
+ }
}
/**
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index 2f0f6bc..49f419f 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -431,6 +431,11 @@
public void configureSurfaces(Collection<Surface> surfaces) {
releaseEGLContext();
+ if (surfaces == null || surfaces.size() == 0) {
+ Log.w(TAG, "No output surfaces configured for GL drawing.");
+ return;
+ }
+
for (Surface s : surfaces) {
// If pixel conversions aren't handled by egl, use a pbuffer
if (LegacyCameraDevice.needsConversion(s)) {
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index 40cda08..898c746 100644
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -47,6 +47,8 @@
* - POLICY_PROHIBITS
* - RESOURCE_BUSY
* - NO_SUCH_DEVICE
+ * - NOT_SUPPORTED
+ * - TOO_MANY_USERS
*/
public static final int EACCES = -13;
public static final int EBUSY = -16;
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 8ad9463..d86dd5e7 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -185,6 +185,7 @@
public static final int RESULT_TARGET_NOT_AVAILABLE = 3;
public static final int RESULT_ALREADY_IN_PROGRESS = 4;
public static final int RESULT_EXCEPTION = 5;
+ public static final int RESULT_INCORRECT_MODE = 6;
private static final int[] ADDRESS_TO_TYPE = {
DEVICE_TV, // ADDR_TV
diff --git a/core/java/android/net/PSKKeyManager.java b/core/java/android/net/PSKKeyManager.java
new file mode 100644
index 0000000..92dd141
--- /dev/null
+++ b/core/java/android/net/PSKKeyManager.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2014 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.net;
+
+import java.net.Socket;
+import javax.crypto.SecretKey;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Provider of key material for pre-shared key (PSK) key exchange used in TLS-PSK cipher suites.
+ *
+ * <h3>Overview of TLS-PSK</h3>
+ *
+ * <p>TLS-PSK is a set of TLS/SSL cipher suites which rely on a symmetric pre-shared key (PSK) to
+ * secure the TLS/SSL connection and mutually authenticate its peers. These cipher suites may be
+ * a more natural fit compared to conventional public key based cipher suites in some scenarios
+ * where communication between peers is bootstrapped via a separate step (for example, a pairing
+ * step) and requires both peers to authenticate each other. In such scenarios a symmetric key (PSK)
+ * can be exchanged during the bootstrapping step, removing the need to generate and exchange public
+ * key pairs and X.509 certificates.</p>
+ *
+ * <p>When a TLS-PSK cipher suite is used, both peers have to use the same key for the TLS/SSL
+ * handshake to succeed. Thus, both peers are implicitly authenticated by a successful handshake.
+ * This removes the need to use a {@code TrustManager} in conjunction with this {@code KeyManager}.
+ * </p>
+ *
+ * <h3>Supporting multiple keys</h3>
+ *
+ * <p>A peer may have multiple keys to choose from. To help choose the right key, during the handshake
+ * the server can provide a <em>PSK identity hint</em> to the client, and the client can provide a
+ * <em>PSK identity</em> to the server. The contents of these two pieces of information are specific
+ * to application-level protocols.</p>
+ *
+ * <p><em>NOTE: Both the PSK identity hint and the PSK identity are transmitted in cleartext.
+ * Moreover, these data are received and processed prior to peer having been authenticated. Thus,
+ * they must not contain or leak key material or other sensitive information, and should be
+ * treated (e.g., parsed) with caution, as untrusted data.</em></p>
+ *
+ * <p>The high-level flow leading to peers choosing a key during TLS/SSL handshake is as follows:
+ * <ol>
+ * <li>Server receives a handshake request from client.
+ * <li>Server replies, optionally providing a PSK identity hint to client.</li>
+ * <li>Client chooses the key.</li>
+ * <li>Client provides a PSK identity of the chosen key to server.</li>
+ * <li>Server chooses the key.</li>
+ * </ol></p>
+ *
+ * <p>In the flow above, either peer can signal that they do not have a suitable key, in which case
+ * the the handshake will be aborted immediately. This may enable a network attacker who does not
+ * know the key to learn which PSK identity hints or PSK identities are supported. If this is a
+ * concern then a randomly generated key should be used in the scenario where no key is available.
+ * This will lead to the handshake aborting later, due to key mismatch -- same as in the scenario
+ * where a key is available -- making it appear to the attacker that all PSK identity hints and PSK
+ * identities are supported.</p>
+ *
+ * <h3>Maximum sizes</h3>
+ *
+ * <p>The maximum supported sizes are as follows:
+ * <ul>
+ * <li>256 bytes for keys (see {@link #MAX_KEY_LENGTH_BYTES}),</li>
+ * <li>128 bytes for PSK identity and PSK identity hint (in modified UTF-8 representation) (see
+ * {@link #MAX_IDENTITY_LENGTH_BYTES} and {@link #MAX_IDENTITY_HINT_LENGTH_BYTES}).</li>
+ * </ul></p>
+ *
+ * <h3>Example</h3>
+ * The following example illustrates how to create an {@code SSLContext} which enables the use of
+ * TLS-PSK in {@code SSLSocket}, {@code SSLServerSocket} and {@code SSLEngine} instances obtained
+ * from it.
+ * <pre> {@code
+ * PSKKeyManager myPskKeyManager = ...;
+ *
+ * SSLContext sslContext = SSLContext.getInstance("TLS");
+ * sslContext.init(
+ * new KeyManager[] {myPskKeyManager},
+ * new TrustManager[0], // No TrustManagers needed in TLS-PSK
+ * null // Use the default source of entropy
+ * );
+ *
+ * SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(...);
+ * // Enable a TLS-PSK cipher suite (no TLS-PSK cipher suites are enabled by default)
+ * sslSocket.setEnabledCipherSuites(new String[] {"TLS_PSK_WITH_AES_128_CBC_SHA"});
+ * sslSocket.startHandshake();
+ * }</pre>
+ */
+public interface PSKKeyManager extends com.android.org.conscrypt.PSKKeyManager {
+ // IMPLEMENTATION DETAILS: This class exists only because the default implemenetation of the
+ // TLS/SSL JSSE provider (currently Conscrypt) cannot depend on Android framework classes.
+ // As a result, this framework class simply extends the PSKKeyManager interface from Conscrypt
+ // without adding any new methods or fields. Moreover, for technical reasons (Conscrypt classes
+ // are "hidden") this class replaces the Javadoc of Conscrypt's PSKKeyManager.
+
+ /**
+ * Maximum supported length (in bytes) for PSK identity hint (in modified UTF-8 representation).
+ */
+ int MAX_IDENTITY_HINT_LENGTH_BYTES =
+ com.android.org.conscrypt.PSKKeyManager.MAX_IDENTITY_HINT_LENGTH_BYTES;
+
+ /** Maximum supported length (in bytes) for PSK identity (in modified UTF-8 representation). */
+ int MAX_IDENTITY_LENGTH_BYTES =
+ com.android.org.conscrypt.PSKKeyManager.MAX_IDENTITY_LENGTH_BYTES;
+
+ /** Maximum supported length (in bytes) for PSK. */
+ int MAX_KEY_LENGTH_BYTES = com.android.org.conscrypt.PSKKeyManager.MAX_KEY_LENGTH_BYTES;
+
+ /**
+ * Gets the PSK identity hint to report to the client to help agree on the PSK for the provided
+ * socket.
+ *
+ * @return PSK identity hint to be provided to the client or {@code null} to provide no hint.
+ */
+ @Override
+ String chooseServerKeyIdentityHint(Socket socket);
+
+ /**
+ * Gets the PSK identity hint to report to the client to help agree on the PSK for the provided
+ * engine.
+ *
+ * @return PSK identity hint to be provided to the client or {@code null} to provide no hint.
+ */
+ @Override
+ String chooseServerKeyIdentityHint(SSLEngine engine);
+
+ /**
+ * Gets the PSK identity to report to the server to help agree on the PSK for the provided
+ * socket.
+ *
+ * @param identityHint identity hint provided by the server or {@code null} if none provided.
+ *
+ * @return PSK identity to provide to the server. {@code null} is permitted but will be
+ * converted into an empty string.
+ */
+ @Override
+ String chooseClientKeyIdentity(String identityHint, Socket socket);
+
+ /**
+ * Gets the PSK identity to report to the server to help agree on the PSK for the provided
+ * engine.
+ *
+ * @param identityHint identity hint provided by the server or {@code null} if none provided.
+ *
+ * @return PSK identity to provide to the server. {@code null} is permitted but will be
+ * converted into an empty string.
+ */
+ @Override
+ String chooseClientKeyIdentity(String identityHint, SSLEngine engine);
+
+ /**
+ * Gets the PSK to use for the provided socket.
+ *
+ * @param identityHint identity hint provided by the server to help select the key or
+ * {@code null} if none provided.
+ * @param identity identity provided by the client to help select the key.
+ *
+ * @return key or {@code null} to signal to peer that no suitable key is available and to abort
+ * the handshake.
+ */
+ @Override
+ SecretKey getKey(String identityHint, String identity, Socket socket);
+
+ /**
+ * Gets the PSK to use for the provided engine.
+ *
+ * @param identityHint identity hint provided by the server to help select the key or
+ * {@code null} if none provided.
+ * @param identity identity provided by the client to help select the key.
+ *
+ * @return key or {@code null} to signal to peer that no suitable key is available and to abort
+ * the handshake.
+ */
+ @Override
+ SecretKey getKey(String identityHint, String identity, SSLEngine engine);
+}
diff --git a/core/java/android/os/BatteryManagerInternal.java b/core/java/android/os/BatteryManagerInternal.java
new file mode 100644
index 0000000..f3a95b9
--- /dev/null
+++ b/core/java/android/os/BatteryManagerInternal.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 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.os;
+
+/**
+ * Battery manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class BatteryManagerInternal {
+ /**
+ * Returns true if the device is plugged into any of the specified plug types.
+ */
+ public abstract boolean isPowered(int plugTypeSet);
+
+ /**
+ * Returns the current plug type.
+ */
+ public abstract int getPlugType();
+
+ /**
+ * Returns battery level as a percentage.
+ */
+ public abstract int getBatteryLevel();
+
+ /**
+ * Returns whether we currently consider the battery level to be low.
+ */
+ public abstract boolean getBatteryLevelLow();
+
+ /**
+ * Returns a non-zero value if an unsupported charger is attached.
+ */
+ public abstract int getInvalidCharger();
+}
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 69b828f..08a15eb 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -16,8 +16,6 @@
package android.os;
-import android.view.WindowManagerPolicy;
-
/**
* Power manager local system service interface.
*
@@ -57,12 +55,9 @@
public abstract boolean getLowPowerModeEnabled();
+ public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
+
public interface LowPowerModeListener {
public void onLowPowerModeChanged(boolean enabled);
}
-
- public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
-
- // TODO: Remove this and retrieve as a local service instead.
- public abstract void setPolicy(WindowManagerPolicy policy);
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index ba66e65..1e7d7f1 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -7963,8 +7963,7 @@
actualContext = ((ContextWrapper) actualContext).getBaseContext();
}
final int intentFlags = (actualContext instanceof Activity)
- ? Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
- : Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK;
+ ? 0 : Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK;
// Launch pivot dialog through intent for now
final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags);
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 2fcec52..5fd597b 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -22,12 +22,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
+import android.util.Slog;
/**
* A class that coordinates access to the fingerprint hardware.
@@ -36,31 +38,40 @@
public class FingerprintManager {
private static final String TAG = "FingerprintManager";
private static final boolean DEBUG = true;
- private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
- private static final String FINGERPRINT_SERVICE_CLASS =
- "com.android.service.fingerprint.FingerprintService";
private static final int MSG_ENROLL_RESULT = 100;
- private static final int MSG_SCANNED = 101;
- private static final int MSG_ERROR = 102;
- private static final int MSG_REMOVED = 103;
+ private static final int MSG_ACQUIRED = 101;
+ private static final int MSG_PROCESSED = 102;
+ private static final int MSG_ERROR = 103;
+ private static final int MSG_REMOVED = 104;
+ // Errors generated by layers above HAL
public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
- public static final int FINGERPRINT_ERROR = -1; // One of the error messages below.
- // Progress messages.
- public static final int FINGERPRINT_SCANNED = 1;
- public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2;
+ // Message types. Must agree with HAL (fingerprint.h)
+ public static final int FINGERPRINT_ERROR = -1;
+ public static final int FINGERPRINT_ACQUIRED = 1;
+ public static final int FINGERPRINT_PROCESSED = 2;
+ public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3;
public static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
- // Error messages. Must agree with fingerprint HAL definitions.
+ // Error messages. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
- public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
+ public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+ // FINGERPRINT_ACQUIRED messages. Must agree with HAL (fingerprint.h)
+ public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
+ public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
+ public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
+ public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4;
+ public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8;
+ public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16;
+
private IFingerprintService mService;
private FingerprintManagerReceiver mClientReceiver;
private Context mContext;
+ private IBinder mToken = new Binder();
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
@@ -69,8 +80,11 @@
case MSG_ENROLL_RESULT:
mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
break;
- case MSG_SCANNED:
- mClientReceiver.onScanned(msg.arg1, msg.arg2);
+ case MSG_ACQUIRED:
+ mClientReceiver.onAcquired(msg.arg1);
+ break;
+ case MSG_PROCESSED:
+ mClientReceiver.onProcessed(msg.arg1);
break;
case MSG_ERROR:
mClientReceiver.onError(msg.arg1);
@@ -82,45 +96,29 @@
}
};
- public FingerprintManager(Context context) {
+ /**
+ * @hide
+ */
+ public FingerprintManager(Context context, IFingerprintService service) {
mContext = context;
- // Connect to service...
- Intent intent = new Intent();
- intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
- if (!context.bindServiceAsUser(intent, mFingerprintConnection,
- Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF)) {
- if (DEBUG) Log.v(TAG, "Can't bind to " + FINGERPRINT_SERVICE_CLASS);
+ mService = service;
+ if (mService == null) {
+ Slog.v(TAG, "FingerprintManagerService was null");
}
}
- private final ServiceConnection mFingerprintConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) Log.v(TAG, "Connected to FingerprintService");
- mService = IFingerprintService.Stub.asInterface(service);
- try {
- mService.startListening(mServiceReceiver, getCurrentUserId());
- } catch (RemoteException e) {
- if (DEBUG) Log.v(TAG, "Failed to set callback", e);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Log.v(TAG, "Disconnected from FingerprintService");
- mService = null;
- }
- };
-
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
public void onEnrollResult(int fingerprintId, int remaining) {
mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
}
- public void onScanned(int fingerprintId, int confidence) {
- mHandler.obtainMessage(MSG_SCANNED, fingerprintId, confidence)
- .sendToTarget();;
+ public void onAcquired(int acquireInfo) {
+ mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0).sendToTarget();
+ }
+
+ public void onProcessed(int fingerprintId) {
+ mHandler.obtainMessage(MSG_PROCESSED, fingerprintId, 0).sendToTarget();
}
public void onError(int error) {
@@ -151,12 +149,14 @@
*/
public void enroll(long timeout) {
if (mServiceReceiver == null) {
- throw new IllegalStateException("enroll: Call registerCallback() first");
+ sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
+ return;
}
if (mService != null) try {
- mService.enroll(timeout, getCurrentUserId());
+ mService.enroll(mToken, timeout, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception while enrolling: ", e);
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
@@ -166,10 +166,19 @@
* @param fingerprintId
*/
public void remove(int fingerprintId) {
- if (mService != null) try {
- mService.remove(fingerprintId, getCurrentUserId());
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
+ if (mServiceReceiver == null) {
+ sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
+ return;
+ }
+ if (mService != null) {
+ try {
+ mService.remove(mToken, fingerprintId, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
+ }
+ } else {
+ Log.w(TAG, "remove(): Service not connected!");
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
@@ -181,10 +190,13 @@
mClientReceiver = receiver;
if (mService != null) {
try {
- mService.startListening(mServiceReceiver, getCurrentUserId());
+ mService.startListening(mToken, mServiceReceiver, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in startListening(): ", e);
}
+ } else {
+ Log.w(TAG, "startListening(): Service not connected!");
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
@@ -201,15 +213,38 @@
* Stops the client from listening to fingerprint events.
*/
public void stopListening() {
- mClientReceiver = null;
if (mService != null) {
try {
- mService.stopListening(getCurrentUserId());
+ mService.stopListening(mToken, getCurrentUserId());
+ mClientReceiver = null;
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in stopListening(): ", e);
}
} else {
Log.w(TAG, "stopListening(): Service not connected!");
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
+
+ public void enrollCancel() {
+ if (mServiceReceiver == null) {
+ sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
+ return;
+ }
+ if (mService != null) {
+ try {
+ mService.enrollCancel(mToken, getCurrentUserId());
+ mClientReceiver = null;
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in enrollCancel(): ", e);
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+ }
+ } else {
+ Log.w(TAG, "enrollCancel(): Service not connected!");
+ }
+ }
+
+ private void sendError(int msg, int arg1, int arg2) {
+ mHandler.obtainMessage(msg, arg1, arg2);
+ }
}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
index 34f1655..e5193f5 100644
--- a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
+++ b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
@@ -30,18 +30,32 @@
public void onEnrollResult(int fingerprintId, int remaining) { }
/**
- * Fingerprint scan detected. Most clients will use this function to detect a fingerprint
+ * Fingerprint touch detected, but not processed yet. Clients will use this message to
+ * determine a good or bad scan before the fingerprint is processed. This is meant for the
+ * client to provide feedback about the scan or alert the user that recognition is to follow.
*
- * @param fingerprintId is the finger the hardware has detected.
- * @param confidence from 0 (no confidence) to 65535 (high confidence). Fingerprint 0 has
- * special meaning - the finger wasn't recognized.
+ * @param acquiredInfo one of:
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_GOOD},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_PARTIAL},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_INSUFFICIENT},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_IMAGER_DIRTY},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_SLOW},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_FAST}
*/
- public void onScanned(int fingerprintId, int confidence) { }
+ public void onAcquired(int acquiredInfo) { }
+
+ /**
+ * Fingerprint has been detected and processed. A non-zero return indicates a valid
+ * fingerprint was detected.
+ *
+ * @param fingerprintId the finger id, or 0 if not recognized.
+ */
+ public void onProcessed(int fingerprintId) { }
/**
* An error was detected during scan or enrollment. One of
* {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
- * {@link FingerprintManager#FINGERPRINT_ERROR_BAD_CAPTURE} or
+ * {@link FingerprintManager#FINGERPRINT_ERROR_UNABLE_TO_PROCESS} or
* {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
* {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
*
diff --git a/core/java/android/service/fingerprint/FingerprintService.java b/core/java/android/service/fingerprint/FingerprintService.java
deleted file mode 100644
index c7fa7cd..0000000
--- a/core/java/android/service/fingerprint/FingerprintService.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/**
- * Copyright (C) 2014 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.service.fingerprint;
-
-import android.app.Service;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Slog;
-
-import java.io.PrintWriter;
-import java.util.HashMap;
-
-/**
- * A service to manage multiple clients that want to access the fingerprint HAL API.
- * The service is responsible for maintaining a list of clients and dispatching all
- * fingerprint -related events.
- *
- * @hide
- */
-public class FingerprintService extends Service {
- private final String TAG = FingerprintService.class.getSimpleName() +
- "[" + getClass().getSimpleName() + "]";
- private static final boolean DEBUG = true;
- HashMap<IFingerprintServiceReceiver, ClientData> mClients =
- new HashMap<IFingerprintServiceReceiver, ClientData>();
-
- private static final int MSG_NOTIFY = 10;
-
- Handler mHandler = new Handler() {
- public void handleMessage(android.os.Message msg) {
- switch (msg.what) {
- case MSG_NOTIFY:
- handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
- break;
-
- default:
- Slog.w(TAG, "Unknown message:" + msg.what);
- }
- }
- };
-
- private static final int STATE_IDLE = 0;
- private static final int STATE_LISTENING = 1;
- private static final int STATE_ENROLLING = 2;
- private static final int STATE_DELETING = 3;
- private static final long MS_PER_SEC = 1000;
-
- private static final class ClientData {
- public IFingerprintServiceReceiver receiver;
- int state;
- int userId;
- }
-
- @Override
- public final IBinder onBind(Intent intent) {
- if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
- return new FingerprintServiceWrapper();
- }
-
- // JNI methods to communicate from FingerprintManagerService to HAL
- native int nativeEnroll(int timeout);
- native int nativeRemove(int fingerprintId);
-
- // JNI methods for communicating from HAL to clients
- void notify(int msg, int arg1, int arg2) {
- mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
- }
-
- void handleNotify(int msg, int arg1, int arg2) {
- for (int i = 0; i < mClients.size(); i++) {
- ClientData clientData = mClients.get(i);
- switch (msg) {
- case FingerprintManager.FINGERPRINT_ERROR: {
- if (clientData.state != STATE_IDLE) {
- // FINGERPRINT_ERROR_HW_UNAVAILABLE
- // FINGERPRINT_ERROR_BAD_CAPTURE
- // FINGERPRINT_ERROR_TIMEOUT
- // FINGERPRINT_ERROR_NO_SPACE
- final int error = arg1;
- clientData.state = STATE_IDLE;
- if (clientData.receiver != null) {
- try {
- clientData.receiver.onError(error);
- } catch (RemoteException e) {
- Slog.e(TAG, "can't send message to client. Did it die?", e);
- }
- }
- }
- }
- break;
- case FingerprintManager.FINGERPRINT_SCANNED: {
- final int fingerId = arg1;
- final int confidence = arg2;
- if (clientData.state == STATE_LISTENING && clientData.receiver != null) {
- try {
- clientData.receiver.onScanned(fingerId, confidence);
- } catch (RemoteException e) {
- Slog.e(TAG, "can't send message to client. Did it die?", e);
- }
- }
- break;
- }
- case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
- if (clientData.state == STATE_ENROLLING) {
- final int fingerId = arg1;
- final int remaining = arg2;
- if (remaining == 0) {
- FingerprintUtils.addFingerprintIdForUser(fingerId,
- getContentResolver(), clientData.userId);
- clientData.state = STATE_IDLE; // Nothing left to do
- }
- if (clientData.receiver != null) {
- try {
- clientData.receiver.onEnrollResult(fingerId, remaining);
- } catch (RemoteException e) {
- Slog.e(TAG, "can't send message to client. Did it die?", e);
- }
- }
- }
- break;
- }
- case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
- int fingerId = arg1;
- if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
- if (clientData.state == STATE_DELETING) {
- FingerprintUtils.removeFingerprintIdForUser(fingerId, getContentResolver(),
- clientData.userId);
- if (clientData.receiver != null) {
- try {
- clientData.receiver.onRemoved(fingerId);
- } catch (RemoteException e) {
- Slog.e(TAG, "can't send message to client. Did it die?", e);
- }
- }
- }
- }
- break;
- }
- }
- }
-
- int enroll(IFingerprintServiceReceiver receiver, long timeout, int userId) {
- ClientData clientData = mClients.get(receiver);
- if (clientData != null) {
- if (clientData.userId != userId) throw new IllegalStateException("Bad user");
- clientData.state = STATE_ENROLLING;
- return nativeEnroll((int) (timeout / MS_PER_SEC));
- }
- return -1;
- }
-
- int remove(IFingerprintServiceReceiver receiver, int fingerId, int userId) {
- ClientData clientData = mClients.get(receiver);
- if (clientData != null) {
- if (clientData.userId != userId) throw new IllegalStateException("Bad user");
- clientData.state = STATE_DELETING;
- // The fingerprint id will be removed when we get confirmation from the HAL
- return nativeRemove(fingerId);
- }
- return -1;
- }
-
- void startListening(IFingerprintServiceReceiver receiver, int userId) {
- ClientData clientData = new ClientData();
- clientData.state = STATE_LISTENING;
- clientData.receiver = receiver;
- clientData.userId = userId;
- mClients.put(receiver, clientData);
- }
-
- void stopListening(IFingerprintServiceReceiver receiver, int userId) {
- ClientData clientData = mClients.get(receiver);
- if (clientData != null) {
- clientData.state = STATE_IDLE;
- clientData.userId = -1;
- clientData.receiver = null;
- }
- mClients.remove(receiver);
- }
-
- private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
- IFingerprintServiceReceiver mReceiver;
- public int enroll(long timeout, int userId) {
- return mReceiver != null ? FingerprintService.this.enroll(mReceiver, timeout, userId)
- : FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER;
- }
-
- public int remove(int fingerprintId, int userId) {
- return FingerprintService.this.remove(mReceiver, fingerprintId, userId);
- }
-
- public void startListening(IFingerprintServiceReceiver receiver, int userId) {
- mReceiver = receiver;
- FingerprintService.this.startListening(receiver, userId);
- }
-
- public void stopListening(int userId) {
- FingerprintService.this.stopListening(mReceiver, userId);
- }
- }
-}
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
index 81a2aac..f4b5526 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -18,10 +18,12 @@
import android.content.ContentResolver;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
import java.util.Arrays;
+public
class FingerprintUtils {
private static final boolean DEBUG = true;
private static final String TAG = "FingerprintUtils";
@@ -30,13 +32,16 @@
String fingerIdsRaw = Settings.Secure.getStringForUser(res,
Settings.Secure.USER_FINGERPRINT_IDS, userId);
- String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
- int result[] = new int[fingerStringIds.length];
- for (int i = 0; i < result.length; i++) {
- try {
- result[i] = Integer.decode(fingerStringIds[i]);
- } catch (NumberFormatException e) {
- if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+ int result[] = {};
+ if (!TextUtils.isEmpty(fingerIdsRaw)) {
+ String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
+ result = new int[fingerStringIds.length];
+ for (int i = 0; i < result.length; i++) {
+ try {
+ result[i] = Integer.decode(fingerStringIds[i]);
+ } catch (NumberFormatException e) {
+ if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+ }
}
}
return result;
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
index e92c20c..43d5e9a 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -22,17 +22,20 @@
* Communication channel from client to the fingerprint service.
* @hide
*/
-interface IFingerprintService {
- // Returns 0 if successfully started, -1 otherwise
- int enroll(long timeout, int userId);
+oneway interface IFingerprintService {
+ // Any errors resulting from this call will be returned to the listener
+ void enroll(IBinder token, long timeout, int userId);
+
+ // Any errors resulting from this call will be returned to the listener
+ void enrollCancel(IBinder token, int userId);
- // Returns 0 if fingerprintId's template can be removed, -1 otherwise
- int remove(int fingerprintId, int userId);
+ // Any errors resulting from this call will be returned to the listener
+ void remove(IBinder token, int fingerprintId, int userId);
// Start listening for fingerprint events. This has the side effect of starting
// the hardware if not already started.
- oneway void startListening(IFingerprintServiceReceiver receiver, int userId);
+ void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId);
// Stops listening for fingerprints
- oneway void stopListening(int userId);
+ void stopListening(IBinder token, int userId);
}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
index 4826b59..af4128f 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -24,7 +24,8 @@
*/
oneway interface IFingerprintServiceReceiver {
void onEnrollResult(int fingerprintId, int remaining);
- void onScanned(int fingerprintId, int confidence);
+ void onAcquired(int acquiredInfo);
+ void onProcessed(int fingerprintId);
void onError(int error);
void onRemoved(int fingerprintId);
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 0a4f641..508769d 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -206,6 +206,10 @@
// like CircularPropagation
EpicenterCallback mEpicenterCallback;
+ // For Fragment shared element transitions, linking views explicitly by mismatching
+ // viewNames.
+ ArrayMap<String, String> mNameOverrides;
+
/**
* Constructs a Transition object with no target objects. A transition with
* no targets defaults to running on all target objects in the scene hierarchy
@@ -1347,6 +1351,21 @@
} else {
captureHierarchy(sceneRoot, start);
}
+ if (!start && mNameOverrides != null) {
+ int numOverrides = mNameOverrides.size();
+ ArrayList<View> overriddenViews = new ArrayList<View>(numOverrides);
+ for (int i = 0; i < numOverrides; i++) {
+ String fromName = mNameOverrides.keyAt(i);
+ overriddenViews.add(mStartValues.nameValues.remove(fromName));
+ }
+ for (int i = 0; i < numOverrides; i++) {
+ View view = overriddenViews.get(i);
+ if (view != null) {
+ String toName = mNameOverrides.valueAt(i);
+ mStartValues.nameValues.put(toName, view);
+ }
+ }
+ }
}
static void addViewValues(TransitionValuesMaps transitionValuesMaps,
@@ -1400,10 +1419,12 @@
mStartValues.viewValues.clear();
mStartValues.idValues.clear();
mStartValues.itemIdValues.clear();
+ mStartValues.nameValues.clear();
} else {
mEndValues.viewValues.clear();
mEndValues.idValues.clear();
mEndValues.itemIdValues.clear();
+ mEndValues.nameValues.clear();
}
}
@@ -1866,6 +1887,20 @@
return mCanRemoveViews;
}
+ /**
+ * Sets the shared element names -- a mapping from a name at the start state to
+ * a different name at the end state.
+ * @hide
+ */
+ public void setNameOverrides(ArrayMap<String, String> overrides) {
+ mNameOverrides = overrides;
+ }
+
+ /** @hide */
+ public ArrayMap<String, String> getNameOverrides() {
+ return mNameOverrides;
+ }
+
@Override
public String toString() {
return toString("");
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 698b563..c04be4f 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -168,30 +168,106 @@
@Override
public TransitionSet addTarget(View target) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).addTarget(target);
+ }
return (TransitionSet) super.addTarget(target);
}
@Override
public TransitionSet addTarget(int targetId) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).addTarget(targetId);
+ }
return (TransitionSet) super.addTarget(targetId);
}
@Override
+ public TransitionSet addTarget(String targetName) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).addTarget(targetName);
+ }
+ return (TransitionSet) super.addTarget(targetName);
+ }
+
+ @Override
+ public TransitionSet addTarget(Class targetType) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).addTarget(targetType);
+ }
+ return (TransitionSet) super.addTarget(targetType);
+ }
+
+ @Override
public TransitionSet addListener(TransitionListener listener) {
return (TransitionSet) super.addListener(listener);
}
@Override
public TransitionSet removeTarget(int targetId) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).removeTarget(targetId);
+ }
return (TransitionSet) super.removeTarget(targetId);
}
@Override
public TransitionSet removeTarget(View target) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).removeTarget(target);
+ }
return (TransitionSet) super.removeTarget(target);
}
@Override
+ public TransitionSet removeTarget(Class target) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).removeTarget(target);
+ }
+ return (TransitionSet) super.removeTarget(target);
+ }
+
+ @Override
+ public TransitionSet removeTarget(String target) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).removeTarget(target);
+ }
+ return (TransitionSet) super.removeTarget(target);
+ }
+
+ @Override
+ public Transition excludeTarget(View target, boolean exclude) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).excludeTarget(target, exclude);
+ }
+ return super.excludeTarget(target, exclude);
+ }
+
+ @Override
+ public Transition excludeTarget(String targetViewName, boolean exclude) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).excludeTarget(targetViewName, exclude);
+ }
+ return super.excludeTarget(targetViewName, exclude);
+ }
+
+ @Override
+ public Transition excludeTarget(int targetId, boolean exclude) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).excludeTarget(targetId, exclude);
+ }
+ return super.excludeTarget(targetId, exclude);
+ }
+
+ @Override
+ public Transition excludeTarget(Class type, boolean exclude) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).excludeTarget(type, exclude);
+ }
+ return super.excludeTarget(type, exclude);
+ }
+
+ @Override
public TransitionSet removeListener(TransitionListener listener) {
return (TransitionSet) super.removeListener(listener);
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 0f7638b..c6c8337 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -18,6 +18,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
import android.view.View;
import android.view.ViewGroup;
@@ -272,15 +275,23 @@
if (startView.getParent() == null) {
// no parent - safe to use
overlayView = startView;
- } else if (startView.getParent() instanceof View &&
- startView.getParent().getParent() == null) {
+ } else if (startView.getParent() instanceof View) {
View startParent = (View) startView.getParent();
- int id = startParent.getId();
- if (id != View.NO_ID && sceneRoot.findViewById(id) != null && mCanRemoveViews) {
- // no parent, but its parent is unparented but the parent
- // hierarchy has been replaced by a new hierarchy with the same id
- // and it is safe to un-parent startView
- overlayView = startView;
+ if (!isValidTarget(startParent)) {
+ if (startView.isAttachedToWindow()) {
+ overlayView = copyViewImage(startView);
+ } else {
+ overlayView = startView;
+ }
+ } else if (startParent.getParent() == null) {
+ int id = startParent.getId();
+ if (id != View.NO_ID && sceneRoot.findViewById(id) != null
+ && mCanRemoveViews) {
+ // no parent, but its parent is unparented but the parent
+ // hierarchy has been replaced by a new hierarchy with the same id
+ // and it is safe to un-parent startView
+ overlayView = startView;
+ }
}
}
}
@@ -378,6 +389,26 @@
return null;
}
+ private View copyViewImage(View view) {
+ int width = view.getWidth();
+ int height = view.getHeight();
+ if (width <= 0 || height <= 0) {
+ return null;
+ }
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ view.draw(canvas);
+ final BitmapDrawable drawable = new BitmapDrawable(bitmap);
+
+ View overlayView = new View(view.getContext());
+ overlayView.setBackground(drawable);
+ int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+ int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
+ overlayView.measure(widthSpec, heightSpec);
+ overlayView.layout(0, 0, width, height);
+ return overlayView;
+ }
+
/**
* The default implementation of this method returns a null Animator. Subclasses should
* override this method to make targets disappear with the desired transition. The
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index d7a913d..181f77e 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -599,6 +599,42 @@
}
/**
+ * Gets the app VSYNC offset, in nanoseconds. This is a positive value indicating
+ * the phase offset of the VSYNC events provided by Choreographer relative to the
+ * display refresh. For example, if Choreographer reports that the refresh occurred
+ * at time N, it actually occurred at (N - appVsyncOffset).
+ * <p>
+ * Apps generally do not need to be aware of this. It's only useful for fine-grained
+ * A/V synchronization.
+ * @hide
+ */
+ public long getAppVsyncOffsetNanos() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.appVsyncOffsetNanos;
+ }
+ }
+
+ /**
+ * This is how far in advance a buffer must be queued for presentation at
+ * a given time. If you want a buffer to appear on the screen at
+ * time N, you must submit the buffer before (N - presentationDeadline).
+ * <p>
+ * The desired presentation time for GLES rendering may be set with
+ * {@link android.opengl.EGLExt#eglPresentationTimeANDROID}. For video decoding, use
+ * {@link android.media.MediaCodec#releaseOutputBuffer(int, long)}. Times are
+ * expressed in nanoseconds, using the system monotonic clock
+ * ({@link System#nanoTime}).
+ * @hide
+ */
+ public long getPresentationDeadlineNanos() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.presentationDeadlineNanos;
+ }
+ }
+
+ /**
* Gets display metrics that describe the size and density of this display.
* <p>
* The size is adjusted based on the current rotation of the display.
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index b0fe0fa..98696c7 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -180,6 +180,20 @@
public float physicalYDpi;
/**
+ * This is a positive value indicating the phase offset of the VSYNC events provided by
+ * Choreographer relative to the display refresh. For example, if Choreographer reports
+ * that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos).
+ */
+ public long appVsyncOffsetNanos;
+
+ /**
+ * This is how far in advance a buffer must be queued for presentation at
+ * a given time. If you want a buffer to appear on the screen at
+ * time N, you must submit the buffer before (N - bufferDeadlineNanos).
+ */
+ public long presentationDeadlineNanos;
+
+ /**
* The state of the display, such as {@link android.view.Display#STATE_ON}.
*/
public int state;
@@ -253,6 +267,8 @@
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
+ && appVsyncOffsetNanos == other.appVsyncOffsetNanos
+ && presentationDeadlineNanos == other.presentationDeadlineNanos
&& state == other.state
&& ownerUid == other.ownerUid
&& Objects.equal(ownerPackageName, other.ownerPackageName);
@@ -286,6 +302,8 @@
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
+ appVsyncOffsetNanos = other.appVsyncOffsetNanos;
+ presentationDeadlineNanos = other.presentationDeadlineNanos;
state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
@@ -314,6 +332,8 @@
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
+ appVsyncOffsetNanos = source.readLong();
+ presentationDeadlineNanos = source.readLong();
state = source.readInt();
ownerUid = source.readInt();
ownerPackageName = source.readString();
@@ -343,6 +363,8 @@
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
+ dest.writeLong(appVsyncOffsetNanos);
+ dest.writeLong(presentationDeadlineNanos);
dest.writeInt(state);
dest.writeInt(ownerUid);
dest.writeString(ownerPackageName);
@@ -450,6 +472,10 @@
sb.append(physicalYDpi);
sb.append(") dpi, layerStack ");
sb.append(layerStack);
+ sb.append(", appVsyncOff ");
+ sb.append(appVsyncOffsetNanos);
+ sb.append(", presDeadline ");
+ sb.append(presentationDeadlineNanos);
sb.append(", type ");
sb.append(Display.typeToString(type));
if (address != null) {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 832d67a..446bbc9 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -404,6 +404,9 @@
@Override
public void scale(float sx, float sy) {
+ // TODO: remove
+ if (sx > 1000000 || sy > 1000000) throw new IllegalArgumentException("invalid scales passed " + sx + ", " + sy);
+
nScale(mRenderer, sx, sy);
}
@@ -544,9 +547,9 @@
///////////////////////////////////////////////////////////////////////////
@Override
- public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
- Paint paint) {
- nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
+ public void drawArc(float left, float top, float right, float bottom,
+ float startAngle, float sweepAngle, boolean useCenter, Paint paint) {
+ nDrawArc(mRenderer, left, top, right, bottom,
startAngle, sweepAngle, useCenter, paint.mNativePaint);
}
@@ -771,8 +774,8 @@
}
@Override
- public void drawOval(RectF oval, Paint paint) {
- nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
+ public void drawOval(float left, float top, float right, float bottom, Paint paint) {
+ nDrawOval(mRenderer, left, top, right, bottom, paint.mNativePaint);
}
private static native void nDrawOval(long renderer, float left, float top,
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 79f19b5..94d8f70 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -458,6 +458,8 @@
public float xDpi;
public float yDpi;
public boolean secure;
+ public long appVsyncOffsetNanos;
+ public long presentationDeadlineNanos;
public PhysicalDisplayInfo() {
}
@@ -479,7 +481,9 @@
&& density == other.density
&& xDpi == other.xDpi
&& yDpi == other.yDpi
- && secure == other.secure;
+ && secure == other.secure
+ && appVsyncOffsetNanos == other.appVsyncOffsetNanos
+ && presentationDeadlineNanos == other.presentationDeadlineNanos;
}
@Override
@@ -495,6 +499,8 @@
xDpi = other.xDpi;
yDpi = other.yDpi;
secure = other.secure;
+ appVsyncOffsetNanos = other.appVsyncOffsetNanos;
+ presentationDeadlineNanos = other.presentationDeadlineNanos;
}
// For debugging purposes
@@ -502,7 +508,8 @@
public String toString() {
return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
+ "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure
- + "}";
+ + ", appVsyncOffset " + appVsyncOffsetNanos
+ + ", bufferDeadline " + presentationDeadlineNanos + "}";
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b9e56f3..9156216 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -25,6 +25,7 @@
import android.annotation.Nullable;
import android.content.ClipData;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -44,6 +45,7 @@
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Shader;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManagerGlobal;
@@ -3187,6 +3189,9 @@
@ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_")
private Drawable mBackground;
+ private ColorStateList mBackgroundTint = null;
+ private PorterDuff.Mode mBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasBackgroundTint = false;
/**
* Display list used for backgrounds.
@@ -4022,6 +4027,16 @@
setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
a.getResourceId(attr, 0)));
break;
+ case R.styleable.View_backgroundTint:
+ // This will get applied later during setBackground().
+ mBackgroundTint = a.getColorStateList(R.styleable.View_backgroundTint);
+ mHasBackgroundTint = true;
+ break;
+ case R.styleable.View_backgroundTintMode:
+ // This will get applied later during setBackground().
+ mBackgroundTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.View_backgroundTintMode, -1), mBackgroundTintMode);
+ break;
}
}
@@ -13432,8 +13447,6 @@
// Destroy any previous software drawing cache if needed
if (mLayerType == LAYER_TYPE_SOFTWARE) {
destroyDrawingCache();
- invalidateParentCaches();
- invalidate(true);
}
mLayerType = layerType;
@@ -13441,13 +13454,10 @@
mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
mRenderNode.setLayerPaint(mLayerPaint);
- if (mLayerType == LAYER_TYPE_SOFTWARE) {
- // LAYER_TYPE_SOFTWARE is handled by View:draw(), so need to invalidate()
- invalidateParentCaches();
- invalidate(true);
- } else {
- invalidateViewProperty(false, false);
- }
+ // draw() behaves differently if we are on a layer, so we need to
+ // invalidate() here
+ invalidateParentCaches();
+ invalidate(true);
}
/**
@@ -15703,7 +15713,7 @@
return;
}
- Drawable d= null;
+ Drawable d = null;
if (resid != 0) {
d = mContext.getDrawable(resid);
}
@@ -15779,8 +15789,9 @@
// Compare the minimum sizes of the old Drawable and the new. If there isn't an old or
// if it has a different minimum size, we should layout again
- if (mBackground == null || mBackground.getMinimumHeight() != background.getMinimumHeight() ||
- mBackground.getMinimumWidth() != background.getMinimumWidth()) {
+ if (mBackground == null
+ || mBackground.getMinimumHeight() != background.getMinimumHeight()
+ || mBackground.getMinimumWidth() != background.getMinimumWidth()) {
requestLayout = true;
}
@@ -15791,6 +15802,8 @@
background.setVisible(getVisibility() == VISIBLE, false);
mBackground = background;
+ applyBackgroundTint();
+
if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
mPrivateFlags &= ~PFLAG_SKIP_DRAW;
mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND;
@@ -15846,6 +15859,88 @@
}
/**
+ * Applies a tint to the background drawable.
+ * <p>
+ * Subsequent calls to {@link #setBackground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#View_backgroundTint
+ * @attr ref android.R.styleable#View_backgroundTintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setBackgroundTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mBackgroundTint = tint;
+ mBackgroundTintMode = tintMode;
+ mHasBackgroundTint = true;
+
+ applyBackgroundTint();
+ }
+
+ /**
+ * Applies a tint to the background drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setBackground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#View_backgroundTint
+ * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setBackgroundTint(@Nullable ColorStateList tint) {
+ setBackgroundTint(tint, mBackgroundTintMode);
+ }
+
+ /**
+ * @return the tint applied to the background drawable
+ * @attr ref android.R.styleable#View_backgroundTint
+ * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getBackgroundTint() {
+ return mBackgroundTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setBackgroundTint(ColorStateList)}} to the background drawable.
+ * The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#View_backgroundTintMode
+ * @see #setBackgroundTint(ColorStateList)
+ */
+ public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setBackgroundTint(mBackgroundTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the background drawable
+ * @attr ref android.R.styleable#View_backgroundTintMode
+ * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getBackgroundTintMode() {
+ return mBackgroundTintMode;
+ }
+
+ private void applyBackgroundTint() {
+ if (mBackground != null && mHasBackgroundTint) {
+ mBackground = mBackground.mutate();
+ mBackground.setTint(mBackgroundTint, mBackgroundTintMode);
+ }
+ }
+
+ /**
* Sets the padding. The view may add on the space required to display
* the scrollbars, depending on the style and visibility of the scrollbars.
* So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop},
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index dfd5cdf..82e5ddd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -656,7 +656,7 @@
}
public boolean invokeFunctor(long functor, boolean waitForCompletion) {
- if (mAttachInfo.mHardwareRenderer == null || !mAttachInfo.mHardwareRenderer.isEnabled()) {
+ if (mAttachInfo.mHardwareRenderer == null) {
return false;
}
mAttachInfo.mHardwareRenderer.invokeFunctor(functor, waitForCompletion);
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index abed082..321d9d3 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.net.WebAddress;
+import android.webkit.ValueCallback;
/**
* Manages the cookies used by an application's {@link WebView} instances.
@@ -72,7 +73,7 @@
* path and name will be replaced with the new cookie. The cookie being set
* will be ignored if it is expired.
*
- * @param url the URL for which the cookie is set
+ * @param url the URL for which the cookie is to be set
* @param value the cookie as a string, using the format of the 'Set-Cookie'
* HTTP response header
*/
@@ -81,6 +82,29 @@
}
/**
+ * Sets a cookie for the given URL. Any existing cookie with the same host,
+ * path and name will be replaced with the new cookie. The cookie being set
+ * will be ignored if it is expired.
+ * <p>
+ * This method is asynchronous.
+ * If a {@link ValueCallback} is provided,
+ * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+ * thread's {@link android.os.Looper} once the operation is complete.
+ * The value provided to the callback indicates whether the cookie was set successfully.
+ * You can pass {@code null} as the callback if you don't need to know when the operation
+ * completes or whether it succeeded, and in this case it is safe to call the method from a
+ * thread without a Looper.
+ *
+ * @param url the URL for which the cookie is to be set
+ * @param value the cookie as a string, using the format of the 'Set-Cookie'
+ * HTTP response header
+ * @param callback a callback to be executed when the cookie has been set
+ */
+ public void setCookie(String url, String value, ValueCallback<Boolean> callback) {
+ throw new MustOverrideException();
+ }
+
+ /**
* Gets the cookies for the given URL.
*
* @param url the URL for which the cookies are requested
@@ -120,19 +144,57 @@
/**
* Removes all session cookies, which are cookies without an expiration
* date.
+ * @deprecated use {@link #removeSessionCookies(ValueCallback)} instead.
*/
public void removeSessionCookie() {
throw new MustOverrideException();
}
/**
- * Removes all cookies.
+ * Removes all session cookies, which are cookies without an expiration
+ * date.
+ * <p>
+ * This method is asynchronous.
+ * If a {@link ValueCallback} is provided,
+ * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+ * thread's {@link android.os.Looper} once the operation is complete.
+ * The value provided to the callback indicates whether any cookies were removed.
+ * You can pass {@code null} as the callback if you don't need to know when the operation
+ * completes or whether any cookie were removed, and in this case it is safe to call the
+ * method from a thread without a Looper.
+ * @param callback a callback which is executed when the session cookies have been removed
*/
+ public void removeSessionCookies(ValueCallback<Boolean> callback) {
+ throw new MustOverrideException();
+ }
+
+ /**
+ * Removes all cookies.
+ * @deprecated Use {@link #removeAllCookies(ValueCallback)} instead.
+ */
+ @Deprecated
public void removeAllCookie() {
throw new MustOverrideException();
}
/**
+ * Removes all cookies.
+ * <p>
+ * This method is asynchronous.
+ * If a {@link ValueCallback} is provided,
+ * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+ * thread's {@link android.os.Looper} once the operation is complete.
+ * The value provided to the callback indicates whether any cookies were removed.
+ * You can pass {@code null} as the callback if you don't need to know when the operation
+ * completes or whether any cookies were removed, and in this case it is safe to call the
+ * method from a thread without a Looper.
+ * @param callback a callback which is executed when the cookies have been removed
+ */
+ public void removeAllCookies(ValueCallback<Boolean> callback) {
+ throw new MustOverrideException();
+ }
+
+ /**
* Gets whether there are stored cookies.
*
* @return true if there are stored cookies
@@ -153,7 +215,9 @@
/**
* Removes all expired cookies.
+ * @deprecated The WebView handles removing expired cookies automatically.
*/
+ @Deprecated
public void removeExpiredCookie() {
throw new MustOverrideException();
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 08931fe..eb3f882 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -16,11 +16,15 @@
package android.widget;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Insets;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -31,10 +35,16 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
public abstract class AbsSeekBar extends ProgressBar {
private final Rect mTempRect = new Rect();
private Drawable mThumb;
+ private ColorStateList mThumbTint = null;
+ private PorterDuff.Mode mThumbTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasThumbTint = false;
+
private int mThumbOffset;
private boolean mSplitTrack;
@@ -83,6 +93,15 @@
final Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
setThumb(thumb);
+ if (a.hasValue(R.styleable.SeekBar_thumbTint)) {
+ mThumbTint = a.getColorStateList(R.styleable.SeekBar_thumbTint);
+ mThumbTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.SeekBar_thumbTintMode, -1), mThumbTintMode);
+ mHasThumbTint = true;
+
+ applyThumbTint();
+ }
+
// Guess thumb offset if thumb != null, but allow layout to override.
final int thumbOffset = a.getDimensionPixelOffset(
com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
@@ -108,7 +127,7 @@
* @param thumb Drawable representing the thumb
*/
public void setThumb(Drawable thumb) {
- boolean needUpdate;
+ final boolean needUpdate;
// This way, calling setThumb again with the same bitmap will result in
// it recalcuating mThumbOffset (if for example it the bounds of the
// drawable changed)
@@ -118,6 +137,7 @@
} else {
needUpdate = false;
}
+
if (thumb != null) {
thumb.setCallback(this);
if (canResolveLayoutDirection()) {
@@ -136,8 +156,12 @@
requestLayout();
}
}
+
mThumb = thumb;
+
+ applyThumbTint();
invalidate();
+
if (needUpdate) {
updateThumbAndTrackPos(getWidth(), getHeight());
if (thumb != null && thumb.isStateful()) {
@@ -160,6 +184,88 @@
}
/**
+ * Applies a tint to the thumb drawable.
+ * <p>
+ * Subsequent calls to {@link #setThumb(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#SeekBar_thumbTint
+ * @attr ref android.R.styleable#SeekBar_thumbTintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setThumbTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mThumbTint = tint;
+ mThumbTintMode = tintMode;
+ mHasThumbTint = true;
+
+ applyThumbTint();
+ }
+
+ /**
+ * Applies a tint to the thumb drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setThumb(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#SeekBar_thumbTint
+ * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setThumbTint(@Nullable ColorStateList tint) {
+ setThumbTint(tint, mThumbTintMode);
+ }
+
+ /**
+ * @return the tint applied to the thumb drawable
+ * @attr ref android.R.styleable#SeekBar_thumbTint
+ * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getThumbTint() {
+ return mThumbTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setThumbTint(ColorStateList)}} to the thumb drawable. The
+ * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#SeekBar_thumbTintMode
+ * @see #setThumbTint(ColorStateList)
+ */
+ public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setThumbTint(mThumbTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the thumb drawable
+ * @attr ref android.R.styleable#SeekBar_thumbTintMode
+ * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getThumbTintMode() {
+ return mThumbTintMode;
+ }
+
+ private void applyThumbTint() {
+ if (mThumb != null && mHasThumbTint) {
+ mThumb = mThumb.mutate();
+ mThumb.setTint(mThumbTint, mThumbTintMode);
+ }
+ }
+
+ /**
* @see #setThumbOffset(int)
*/
public int getThumbOffset() {
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index c934ad7..747d2b1 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -16,11 +16,15 @@
package android.widget;
+import android.annotation.Nullable;
+import android.graphics.PorterDuff;
import com.android.internal.R;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -48,7 +52,12 @@
private boolean mChecked;
private int mButtonResource;
private boolean mBroadcasting;
+
private Drawable mButtonDrawable;
+ private ColorStateList mButtonTint = null;
+ private PorterDuff.Mode mButtonTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasButtonTint = false;
+
private OnCheckedChangeListener mOnCheckedChangeListener;
private OnCheckedChangeListener mOnCheckedChangeWidgetListener;
@@ -74,13 +83,22 @@
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes);
- Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
+ final Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
if (d != null) {
setButtonDrawable(d);
}
- boolean checked = a
- .getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);
+ if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
+ mButtonTint = a.getColorStateList(R.styleable.CompoundButton_buttonTint);
+ mButtonTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.CompoundButton_buttonTintMode, -1), mButtonTintMode);
+ mHasButtonTint = true;
+
+ applyButtonTint();
+ }
+
+ final boolean checked = a.getBoolean(
+ com.android.internal.R.styleable.CompoundButton_checked, false);
setChecked(checked);
a.recycle();
@@ -173,9 +191,11 @@
}
/**
- * Set the background to a given Drawable, identified by its resource id.
+ * Set the button graphic to a given Drawable, identified by its resource
+ * id.
*
- * @param resid the resource id of the drawable to use as the background
+ * @param resid the resource id of the drawable to use as the button
+ * graphic
*/
public void setButtonDrawable(int resid) {
if (resid != 0 && resid == mButtonResource) {
@@ -192,23 +212,114 @@
}
/**
- * Set the background to a given Drawable
+ * Set the button graphic to a given Drawable
*
- * @param d The Drawable to use as the background
+ * @param d The Drawable to use as the button graphic
*/
public void setButtonDrawable(Drawable d) {
- if (d != null) {
+ if (mButtonDrawable != d) {
if (mButtonDrawable != null) {
mButtonDrawable.setCallback(null);
unscheduleDrawable(mButtonDrawable);
}
- d.setCallback(this);
- d.setVisible(getVisibility() == VISIBLE, false);
- mButtonDrawable = d;
- setMinHeight(mButtonDrawable.getIntrinsicHeight());
- }
- refreshDrawableState();
+ mButtonDrawable = d;
+
+ if (d != null) {
+ d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ d.setVisible(getVisibility() == VISIBLE, false);
+ setMinHeight(d.getIntrinsicHeight());
+ applyButtonTint();
+ }
+ }
+ }
+
+ /**
+ * Applies a tint to the button drawable.
+ * <p>
+ * Subsequent calls to {@link #setButtonDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#CompoundButton_buttonTint
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setButtonTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mButtonTint = tint;
+ mButtonTintMode = tintMode;
+ mHasButtonTint = true;
+
+ applyButtonTint();
+ }
+
+ /**
+ * Applies a tint to the button drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setButtonDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#CompoundButton_buttonTint
+ * @see #setButtonTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ public void setButtonTint(@Nullable ColorStateList tint) {
+ setButtonTint(tint, mButtonTintMode);
+ }
+
+ /**
+ * @return the tint applied to the button drawable
+ * @attr ref android.R.styleable#CompoundButton_buttonTint
+ * @see #setButtonTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getButtonTint() {
+ return mButtonTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setButtonTint(ColorStateList)}} to the button drawable. The
+ * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see #setButtonTint(ColorStateList)
+ */
+ public void setButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setButtonTint(mButtonTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the button drawable
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see #setButtonTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getButtonTintMode() {
+ return mButtonTintMode;
+ }
+
+ private void applyButtonTint() {
+ if (mButtonDrawable != null && mHasButtonTint) {
+ mButtonDrawable = mButtonDrawable.mutate();
+ mButtonDrawable.setTint(mButtonTint, mButtonTintMode);
+ }
}
@Override
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 01a6b8a..5a14929 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -18,11 +18,15 @@
import java.util.ArrayList;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -33,6 +37,8 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
/**
* FrameLayout is designed to block out an area on the screen to display
@@ -62,6 +68,9 @@
@ViewDebug.ExportedProperty(category = "drawing")
private Drawable mForeground;
+ private ColorStateList mForegroundTint = null;
+ private PorterDuff.Mode mForegroundTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasForegroundTint = false;
@ViewDebug.ExportedProperty(category = "padding")
private int mForegroundPaddingLeft = 0;
@@ -119,6 +128,15 @@
setMeasureAllChildren(true);
}
+ if (a.hasValue(R.styleable.FrameLayout_foregroundTint)) {
+ mForegroundTint = a.getColorStateList(R.styleable.FrameLayout_foregroundTint);
+ mForegroundTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.FrameLayout_foregroundTintMode, -1), mForegroundTintMode);
+ mHasForegroundTint = true;
+
+ applyForegroundTint();
+ }
+
mForegroundInPadding = a.getBoolean(
com.android.internal.R.styleable.FrameLayout_foregroundInsidePadding, true);
@@ -231,32 +249,34 @@
* into account by ensuring that the children are inset to be placed
* inside of the padding area.
*
- * @param drawable The Drawable to be drawn on top of the children.
+ * @param d The Drawable to be drawn on top of the children.
*
* @attr ref android.R.styleable#FrameLayout_foreground
*/
- public void setForeground(Drawable drawable) {
- if (mForeground != drawable) {
+ public void setForeground(Drawable d) {
+ if (mForeground != d) {
if (mForeground != null) {
mForeground.setCallback(null);
unscheduleDrawable(mForeground);
}
- mForeground = drawable;
+ mForeground = d;
mForegroundPaddingLeft = 0;
mForegroundPaddingTop = 0;
mForegroundPaddingRight = 0;
mForegroundPaddingBottom = 0;
- if (drawable != null) {
+ if (d != null) {
setWillNotDraw(false);
- drawable.setCallback(this);
- if (drawable.isStateful()) {
- drawable.setState(getDrawableState());
+ d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
}
+ applyForegroundTint();
if (mForegroundGravity == Gravity.FILL) {
Rect padding = new Rect();
- if (drawable.getPadding(padding)) {
+ if (d.getPadding(padding)) {
mForegroundPaddingLeft = padding.left;
mForegroundPaddingTop = padding.top;
mForegroundPaddingRight = padding.right;
@@ -281,6 +301,89 @@
return mForeground;
}
+ /**
+ * Applies a tint to the foreground drawable.
+ * <p>
+ * Subsequent calls to {@link #setForeground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#FrameLayout_foregroundTint
+ * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setForegroundTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mForegroundTint = tint;
+ mForegroundTintMode = tintMode;
+ mHasForegroundTint = true;
+
+ applyForegroundTint();
+ }
+
+ /**
+ * Applies a tint to the foreground drawable. Does not modify the current
+ * tint mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setForeground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#FrameLayout_foregroundTint
+ * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setForegroundTint(@Nullable ColorStateList tint) {
+ setForegroundTint(tint, mForegroundTintMode);
+ }
+
+ /**
+ * @return the tint applied to the foreground drawable
+ * @attr ref android.R.styleable#FrameLayout_foregroundTint
+ * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getForegroundTint() {
+ return mForegroundTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setForegroundTint(ColorStateList)}} to the foreground drawable.
+ * The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+ * @see #setForegroundTint(ColorStateList)
+ */
+ public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setForegroundTint(mForegroundTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the foreground
+ * drawable
+ * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+ * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getForegroundTintMode() {
+ return mForegroundTintMode;
+ }
+
+ private void applyForegroundTint() {
+ if (mForeground != null && mHasForegroundTint) {
+ mForeground = mForeground.mutate();
+ mForeground.setTint(mForegroundTint, mForegroundTintMode);
+ }
+ }
+
int getPaddingLeftWithForeground() {
return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
mPaddingLeft + mForegroundPaddingLeft;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index a40b85e..399e087 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -16,8 +16,10 @@
package android.widget;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -30,6 +32,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Xfermode;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -44,6 +47,8 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
import java.io.IOException;
import java.io.InputStream;
@@ -75,13 +80,18 @@
private int mMaxHeight = Integer.MAX_VALUE;
// these are applied to the drawable
- private ColorFilter mColorFilter;
+ private ColorFilter mColorFilter = null;
+ private boolean mHasColorFilter = false;
private Xfermode mXfermode;
private int mAlpha = 255;
private int mViewAlphaScale = 256;
private boolean mColorMod = false;
private Drawable mDrawable = null;
+ private ColorStateList mDrawableTint = null;
+ private PorterDuff.Mode mDrawableTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasDrawableTint = false;
+
private int[] mState = null;
private boolean mMergeState = false;
private int mLevel = 0;
@@ -154,17 +164,21 @@
setMaxHeight(a.getDimensionPixelSize(
com.android.internal.R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
- int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
+ final int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
if (index >= 0) {
setScaleType(sScaleTypeArray[index]);
}
- int tint = a.getInt(com.android.internal.R.styleable.ImageView_tint, 0);
- if (tint != 0) {
- setColorFilter(tint);
+ if (a.hasValue(R.styleable.ImageView_tint)) {
+ mDrawableTint = a.getColorStateList(R.styleable.ImageView_tint);
+ mDrawableTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ImageView_tintMode, -1), mDrawableTintMode);
+ mHasDrawableTint = true;
+
+ applyDrawableTint();
}
-
- int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
+
+ final int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
if (alpha != 255) {
setAlpha(alpha);
}
@@ -435,6 +449,88 @@
}
/**
+ * Applies a tint to the image drawable.
+ * <p>
+ * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ImageView_tint
+ * @attr ref android.R.styleable#ImageView_tintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mDrawableTint = tint;
+ mDrawableTintMode = tintMode;
+ mHasDrawableTint = true;
+
+ applyDrawableTint();
+ }
+
+ /**
+ * Applies a tint to the image drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ImageView_tint
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setTint(@Nullable ColorStateList tint) {
+ setTint(tint, mDrawableTintMode);
+ }
+
+ /**
+ * @return the tint applied to the image drawable
+ * @attr ref android.R.styleable#ImageView_tint
+ * @see #setTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getTint() {
+ return mDrawableTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setTint(ColorStateList)}} to the image drawable. The default
+ * mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ImageView_tintMode
+ * @see #setTint(ColorStateList)
+ */
+ public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setTint(mDrawableTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the image drawable
+ * @attr ref android.R.styleable#ImageView_tintMode
+ * @see #setTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getTintMode() {
+ return mDrawableTintMode;
+ }
+
+ private void applyDrawableTint() {
+ if (mDrawable != null && mHasDrawableTint) {
+ mDrawable = mDrawable.mutate();
+ mDrawable.setTint(mDrawableTint, mDrawableTintMode);
+ }
+ }
+
+ /**
* Sets a Bitmap as the content of this ImageView.
*
* @param bm The bitmap to set
@@ -709,17 +805,20 @@
mDrawable.setCallback(null);
unscheduleDrawable(mDrawable);
}
+
mDrawable = d;
+
if (d != null) {
d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
if (d.isStateful()) {
d.setState(getDrawableState());
}
- d.setLevel(mLevel);
- d.setLayoutDirection(getLayoutDirection());
d.setVisible(getVisibility() == VISIBLE, true);
+ d.setLevel(mLevel);
mDrawableWidth = d.getIntrinsicWidth();
mDrawableHeight = d.getIntrinsicHeight();
+ applyDrawableTint();
applyColorMod();
configureBounds();
} else {
@@ -1177,6 +1276,7 @@
public void setColorFilter(ColorFilter cf) {
if (mColorFilter != cf) {
mColorFilter = cf;
+ mHasColorFilter = true;
mColorMod = true;
applyColorMod();
invalidate();
@@ -1231,7 +1331,9 @@
// re-applied if the Drawable is changed.
if (mDrawable != null && mColorMod) {
mDrawable = mDrawable.mutate();
- mDrawable.setColorFilter(mColorFilter);
+ if (mHasColorFilter) {
+ mDrawable.setColorFilter(mColorFilter);
+ }
mDrawable.setXfermode(mXfermode);
mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
}
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index af32f1c..62a8bec 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -16,13 +16,17 @@
package android.widget;
+import android.annotation.Nullable;
+import android.graphics.PorterDuff;
import com.android.internal.R;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Animatable;
@@ -210,8 +214,26 @@
private Transformation mTransformation;
private AlphaAnimation mAnimation;
private boolean mHasAnimation;
+
private Drawable mIndeterminateDrawable;
+ private ColorStateList mIndeterminateTint = null;
+ private PorterDuff.Mode mIndeterminateTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasIndeterminateTint = false;
+
private Drawable mProgressDrawable;
+
+ private ColorStateList mProgressTint = null;
+ private PorterDuff.Mode mProgressTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasProgressTint = false;
+
+ private ColorStateList mProgressBackgroundTint = null;
+ private PorterDuff.Mode mProgressBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasProgressBackgroundTint = false;
+
+ private ColorStateList mSecondaryProgressTint = null;
+ private PorterDuff.Mode mSecondaryProgressTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasSecondaryProgressTint = false;
+
private Drawable mCurrentDrawable;
Bitmap mSampleTile;
private boolean mNoInvalidate;
@@ -257,11 +279,11 @@
mNoInvalidate = true;
- Drawable drawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
- if (drawable != null) {
+ final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
+ if (progressDrawable != null) {
// Calling this method can set mMaxHeight, make sure the corresponding
// XML attribute for mMaxHeight is read after calling this method
- setProgressDrawableTiled(drawable);
+ setProgressDrawableTiled(progressDrawable);
}
@@ -288,9 +310,10 @@
setSecondaryProgress(
a.getInt(R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
- drawable = a.getDrawable(R.styleable.ProgressBar_indeterminateDrawable);
- if (drawable != null) {
- setIndeterminateDrawableTiled(drawable);
+ final Drawable indeterminateDrawable = a.getDrawable(
+ R.styleable.ProgressBar_indeterminateDrawable);
+ if (indeterminateDrawable != null) {
+ setIndeterminateDrawableTiled(indeterminateDrawable);
}
mOnlyIndeterminate = a.getBoolean(
@@ -303,6 +326,53 @@
mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl);
+ if (a.hasValue(R.styleable.ProgressBar_progressTint)) {
+ mProgressTint = a.getColorStateList(
+ R.styleable.ProgressBar_progressTint);
+ mProgressTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_progressBackgroundTintMode, -1),
+ mProgressTintMode);
+ mHasProgressTint = true;
+
+ applyProgressLayerTint(R.id.progress, mProgressTint,
+ mProgressTintMode, true);
+ }
+
+ if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTint)) {
+ mProgressBackgroundTint = a.getColorStateList(
+ R.styleable.ProgressBar_progressBackgroundTint);
+ mProgressBackgroundTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_progressTintMode, -1),
+ mProgressBackgroundTintMode);
+ mHasProgressBackgroundTint = true;
+
+ applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+ mProgressBackgroundTintMode, false);
+ }
+
+ if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTint)) {
+ mSecondaryProgressTint = a.getColorStateList(
+ R.styleable.ProgressBar_secondaryProgressTint);
+ mSecondaryProgressTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_secondaryProgressTintMode, -1),
+ mSecondaryProgressTintMode);
+ mHasSecondaryProgressTint = true;
+
+ applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+ mSecondaryProgressTintMode, false);
+ }
+
+ if (a.hasValue(R.styleable.ProgressBar_indeterminateTint)) {
+ mIndeterminateTint = a.getColorStateList(
+ R.styleable.ProgressBar_indeterminateTint);
+ mIndeterminateTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_indeterminateTintMode, -1),
+ mIndeterminateTintMode);
+ mHasIndeterminateTint = true;
+
+ applyIndeterminateTint();
+ }
+
a.recycle();
// If not explicitly specified this view is important for accessibility.
@@ -479,16 +549,111 @@
* @see #setIndeterminate(boolean)
*/
public void setIndeterminateDrawable(Drawable d) {
- if (d != null) {
- d.setCallback(this);
+ if (mIndeterminateDrawable != d) {
+ if (mIndeterminateDrawable != null) {
+ mIndeterminateDrawable.setCallback(null);
+ unscheduleDrawable(mIndeterminateDrawable);
+ }
+
+ mIndeterminateDrawable = d;
+
+ if (d != null) {
+ d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ applyIndeterminateTint();
+ }
+
+ if (mIndeterminate) {
+ mCurrentDrawable = d;
+ postInvalidate();
+ }
}
- mIndeterminateDrawable = d;
- if (mIndeterminateDrawable != null && canResolveLayoutDirection()) {
- mIndeterminateDrawable.setLayoutDirection(getLayoutDirection());
- }
- if (mIndeterminate) {
- mCurrentDrawable = d;
- postInvalidate();
+ }
+
+ /**
+ * Applies a tint to the indeterminate drawable.
+ * <p>
+ * Subsequent calls to {@link #setVisibilminateDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setIndeterminateTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mIndeterminateTint = tint;
+ mIndeterminateTintMode = tintMode;
+ mHasIndeterminateTint = true;
+
+ applyIndeterminateTint();
+ }
+
+ /**
+ * Applies a tint to the indeterminate drawable. Does not modify the
+ * current tint mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setIndeterminateDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+ * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setIndeterminateTint(@Nullable ColorStateList tint) {
+ setIndeterminateTint(tint, mIndeterminateTintMode);
+ }
+
+ /**
+ * @return the tint applied to the indeterminate drawable
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+ * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getIndeterminateTint() {
+ return mIndeterminateTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setIndeterminateTint(ColorStateList)} to the indeterminate
+ * drawable. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+ * @see #setIndeterminateTint(ColorStateList)
+ */
+ public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setIndeterminateTint(mIndeterminateTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the indeterminate drawable
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+ * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getIndeterminateTintMode() {
+ return mIndeterminateTintMode;
+ }
+
+ private void applyIndeterminateTint() {
+ if (mIndeterminateDrawable != null && mHasIndeterminateTint) {
+ mIndeterminateDrawable = mIndeterminateDrawable.mutate();
+ mIndeterminateDrawable.setTint(mIndeterminateTint, mIndeterminateTintMode);
}
}
@@ -532,42 +697,340 @@
* @see #setIndeterminate(boolean)
*/
public void setProgressDrawable(Drawable d) {
- boolean needUpdate;
- if (mProgressDrawable != null && d != mProgressDrawable) {
- mProgressDrawable.setCallback(null);
- needUpdate = true;
- } else {
- needUpdate = false;
- }
+ if (mProgressDrawable != d) {
+ if (mProgressDrawable != null) {
+ mProgressDrawable.setCallback(null);
+ unscheduleDrawable(mProgressDrawable);
+ }
- if (d != null) {
- d.setCallback(this);
- if (canResolveLayoutDirection()) {
+ mProgressDrawable = d;
+
+ if (d != null) {
+ d.setCallback(this);
d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+
+ // Make sure the ProgressBar is always tall enough
+ int drawableHeight = d.getMinimumHeight();
+ if (mMaxHeight < drawableHeight) {
+ mMaxHeight = drawableHeight;
+ requestLayout();
+ }
+
+ if (mHasProgressTint) {
+ applyProgressLayerTint(R.id.progress, mProgressTint, mProgressTintMode, true);
+ }
+
+ if (mHasProgressBackgroundTint) {
+ applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+ mProgressBackgroundTintMode, false);
+ }
+
+ if (mHasSecondaryProgressTint) {
+ applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+ mSecondaryProgressTintMode, false);
+ }
}
- // Make sure the ProgressBar is always tall enough
- int drawableHeight = d.getMinimumHeight();
- if (mMaxHeight < drawableHeight) {
- mMaxHeight = drawableHeight;
- requestLayout();
+ if (!mIndeterminate) {
+ mCurrentDrawable = d;
+ postInvalidate();
}
- }
- mProgressDrawable = d;
- if (!mIndeterminate) {
- mCurrentDrawable = d;
- postInvalidate();
- }
- if (needUpdate) {
updateDrawableBounds(getWidth(), getHeight());
updateDrawableState();
+
doRefreshProgress(R.id.progress, mProgress, false, false);
doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
}
}
/**
+ * Applies a tint to the progress indicator, if one exists, or to the
+ * entire progress drawable otherwise.
+ * <p>
+ * The progress indicator should be specified as a layer with
+ * id {@link android.R.id#progress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressTint
+ * @attr ref android.R.styleable#ProgressBar_progressTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setProgressTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mProgressTint = tint;
+ mProgressTintMode = tintMode;
+ mHasProgressTint = true;
+
+ applyProgressLayerTint(R.id.progress, tint, tintMode, true);
+ }
+
+ /**
+ * Applies a tint to the progress indicator, if one exists, or to the
+ * entire progress drawable otherwise. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * The progress indicator should be specified as a layer with
+ * id {@link android.R.id#progress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressTint
+ * @see #setProgressTint(ColorStateList)
+ */
+ public void setProgressTint(@Nullable ColorStateList tint) {
+ setProgressTint(tint, mProgressTintMode);
+ }
+
+ /**
+ * @return the tint applied to the progress drawable
+ * @attr ref android.R.styleable#ProgressBar_progressTint
+ * @see #setProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getProgressTint() {
+ return mProgressTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setProgressTint(ColorStateList)}} to the progress
+ * indicator. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_progressTintMode
+ * @see #setProgressTint(ColorStateList)
+ */
+ public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setProgressTint(mProgressTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the progress drawable
+ * @attr ref android.R.styleable#ProgressBar_progressTintMode
+ * @see #setProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getProgressTintMode() {
+ return mProgressTintMode;
+ }
+
+ /**
+ * Applies a tint to the progress background, if one exists.
+ * <p>
+ * The progress background must be specified as a layer with
+ * id {@link android.R.id#background} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a progress background will automatically mutate the
+ * drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setProgressBackgroundTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mProgressBackgroundTint = tint;
+ mProgressBackgroundTintMode = tintMode;
+ mHasProgressBackgroundTint = true;
+
+ applyProgressLayerTint(R.id.background, tint, tintMode, false);
+ }
+
+ /**
+ * Applies a tint to the progress background, if one exists. Does not
+ * modify the current tint mode, which is
+ * {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * The progress background must be specified as a layer with
+ * id {@link android.R.id#background} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a progress background will automatically mutate the
+ * drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+ * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setProgressBackgroundTint(@Nullable ColorStateList tint) {
+ setProgressBackgroundTint(tint, mProgressBackgroundTintMode);
+ }
+
+ /**
+ * @return the tint applied to the progress background
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+ * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getProgressBackgroundTint() {
+ return mProgressBackgroundTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setProgressBackgroundTint(ColorStateList)}} to the progress
+ * background. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+ * @see #setProgressBackgroundTint(ColorStateList)
+ */
+ public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setProgressBackgroundTint(mProgressBackgroundTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the progress
+ * background
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+ * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getProgressBackgroundTintMode() {
+ return mProgressBackgroundTintMode;
+ }
+
+ /**
+ * Applies a tint to the secondary progress indicator, if one exists.
+ * <p>
+ * The secondary progress indicator must be specified as a layer with
+ * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a secondary progress indicator will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setSecondaryProgressTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mSecondaryProgressTint = tint;
+ mSecondaryProgressTintMode = tintMode;
+ mHasSecondaryProgressTint = true;
+
+ applyProgressLayerTint(R.id.secondaryProgress, tint, tintMode, false);
+ }
+
+ /**
+ * Applies a tint to the secondary progress indicator, if one exists.
+ * Does not modify the current tint mode, which is
+ * {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * The secondary progress indicator must be specified as a layer with
+ * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a secondary progress indicator will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+ * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setSecondaryProgressTint(@Nullable ColorStateList tint) {
+ setSecondaryProgressTint(tint, mSecondaryProgressTintMode);
+ }
+
+ /**
+ * @return the tint applied to the secondary progress drawable
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+ * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getSecondaryProgressTint() {
+ return mSecondaryProgressTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setSecondaryProgressTint(ColorStateList)}} to the secondary
+ * progress indicator. The default mode is
+ * {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+ * @see #setSecondaryProgressTint(ColorStateList)
+ */
+ public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setSecondaryProgressTint(mSecondaryProgressTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the secondary
+ * progress drawable
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+ * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getSecondaryProgressTintMode() {
+ return mSecondaryProgressTintMode;
+ }
+
+ private void applyProgressLayerTint(int layerId, @Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode, boolean shouldFallback) {
+ final Drawable d = mProgressDrawable;
+ if (d != null) {
+ mProgressDrawable = d.mutate();
+
+ Drawable layer = null;
+ if (d instanceof LayerDrawable) {
+ layer = ((LayerDrawable) d).findDrawableByLayerId(layerId);
+ }
+
+ if (shouldFallback && layer == null) {
+ layer = d;
+ }
+
+ if (layer != null) {
+ layer.setTint(tint, tintMode);
+ }
+ }
+ }
+
+ /**
* Define the tileable drawable used to draw the progress bar in
* progress mode.
* <p>
@@ -670,6 +1133,22 @@
}
}
+ private void setDrawableTint(int id, ColorStateList tint, Mode tintMode, boolean fallback) {
+ Drawable layer = null;
+
+ // We expect a layer drawable, so try to find the target ID.
+ final Drawable d = mCurrentDrawable;
+ if (d instanceof LayerDrawable) {
+ layer = ((LayerDrawable) d).findDrawableByLayerId(id);
+ }
+
+ if (fallback && layer == null) {
+ layer = d;
+ }
+
+ layer.mutate().setTint(tint, tintMode);
+ }
+
private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
boolean callBackToApp) {
float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 9601d4a..9914800 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -25,6 +25,7 @@
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -427,9 +428,15 @@
* {@link Adapter#getItemViewType(int) getItemViewType(int)} on the object
* returned from {@link #getAdapter()} will always return 0. Calling
* {@link Adapter#getViewTypeCount() getViewTypeCount()} will always return
- * 1.
+ * 1. On API {@link Build.VERSION_CODES#L} and above, attempting to set an
+ * adapter with more than one view type will throw an
+ * {@link IllegalArgumentException}.
+ *
+ * @param adapter the adapter to set
*
* @see AbsSpinner#setAdapter(SpinnerAdapter)
+ * @throws IllegalArgumentException if the adapter has more than one view
+ * type
*/
@Override
public void setAdapter(SpinnerAdapter adapter) {
@@ -437,6 +444,12 @@
mRecycler.clear();
+ final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ if (targetSdkVersion >= Build.VERSION_CODES.L
+ && adapter != null && adapter.getViewTypeCount() != 1) {
+ throw new IllegalArgumentException("Spinner adapter view type count must be 1");
+ }
+
if (mPopup != null) {
mPopup.setAdapter(new DropDownAdapter(adapter));
} else {
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 960fa49..643225d7 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -16,6 +16,7 @@
package com.android.internal.backup;
+import android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -168,12 +169,25 @@
int startRestore(long token, in PackageInfo[] packages);
/**
- * Get the package name of the next application with data in the backup store.
- * @return The name of one of the packages supplied to {@link #startRestore},
- * or "" (the empty string) if no more backup data is available,
- * or null if an error occurred (the restore should be aborted and rescheduled).
+ * Get the package name of the next application with data in the backup store, plus
+ * a description of the structure of the restored archive: either TYPE_KEY_VALUE for
+ * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream.
+ *
+ * <p>If the package name in the returned RestoreDescription object is the singleton
+ * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available
+ * in the current restore session: all packages described in startRestore() have been
+ * processed.
+ *
+ * <p>If this method returns {@code null}, it means that a transport-level error has
+ * occurred and the entire restore operation should be abandoned.
+ *
+ * @return A RestoreDescription object containing the name of one of the packages
+ * supplied to {@link #startRestore} plus an indicator of the data type of that
+ * restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that
+ * no more packages can be restored in this session; or {@code null} to indicate
+ * a transport-level error.
*/
- String nextRestorePackage();
+ RestoreDescription nextRestorePackage();
/**
* Get the data for the application returned by {@link #nextRestorePackage}.
@@ -188,7 +202,58 @@
*/
void finishRestore();
+ // full backup stuff
+
long requestFullBackupTime();
int performFullBackup(in PackageInfo targetPackage, in ParcelFileDescriptor socket);
int sendBackupData(int numBytes);
+
+ // full restore stuff
+
+ /**
+ * Ask the transport to provide data for the "current" package being restored. This
+ * is the package that was just reported by {@link #nextRestorePackage()} as having
+ * {@link RestoreDescription#TYPE_FULL_STREAM} data.
+ *
+ * The transport writes some data to the socket supplied to this call, and returns
+ * the number of bytes written. The system will then read that many bytes and
+ * stream them to the application's agent for restore, then will call this method again
+ * to receive the next chunk of the archive. This sequence will be repeated until the
+ * transport returns zero indicating that all of the package's data has been delivered
+ * (or returns a negative value indicating some sort of hard error condition at the
+ * transport level).
+ *
+ * <p>After this method returns zero, the system will then call
+ * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+ * application, and the sequence begins again.
+ *
+ * <p>The transport should always close this socket when returning from this method.
+ * Do not cache this socket across multiple calls or you may leak file descriptors.
+ *
+ * @param socket The file descriptor that the transport will use for delivering the
+ * streamed archive. The transport must close this socket in all cases when returning
+ * from this method.
+ * @return 0 when no more data for the current package is available. A positive value
+ * indicates the presence of that many bytes to be delivered to the app. Any negative
+ * return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
+ * indicating a fatal error condition that precludes further restore operations
+ * on the current dataset.
+ */
+ int getNextFullRestoreDataChunk(in ParcelFileDescriptor socket);
+
+ /**
+ * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
+ * data for restore, it will invoke this method to tell the transport that it should
+ * abandon the data download for the current package. The OS will then either call
+ * {@link #nextRestorePackage()} again to move on to restoring the next package in the
+ * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
+ * operation.
+ *
+ * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
+ * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
+ * transport-level failure. If the transport reports an error here, the entire restore
+ * operation will immediately be finished with no further attempts to restore app data.
+ */
+ int abortFullRestore();
+
}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index c9d621d..ff0ee65 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -19,6 +19,7 @@
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupTransport;
+import android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
import android.content.ComponentName;
import android.content.Context;
@@ -63,18 +64,24 @@
private static final String TRANSPORT_DESTINATION_STRING
= "Backing up to debug-only private cache";
+ private static final String INCREMENTAL_DIR = "_delta";
+ private static final String FULL_DATA_DIR = "_full";
+
// The currently-active restore set always has the same (nonzero!) token
private static final long CURRENT_SET_TOKEN = 1;
private Context mContext;
private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
private File mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN));
- private File mCurrentSetIncrementalDir = new File(mCurrentSetDir, "_delta");
- private File mCurrentSetFullDir = new File(mCurrentSetDir, "_full");
+ private File mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR);
+ private File mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR);
private PackageInfo[] mRestorePackages = null;
private int mRestorePackage = -1; // Index into mRestorePackages
- private File mRestoreDataDir;
+ private int mRestoreType;
+ private File mRestoreSetDir;
+ private File mRestoreSetIncrementalDir;
+ private File mRestoreSetFullDir;
private long mRestoreToken;
// Additional bookkeeping for full backup
@@ -361,30 +368,55 @@
mRestorePackages = packages;
mRestorePackage = -1;
mRestoreToken = token;
- mRestoreDataDir = new File(mDataDir, Long.toString(token));
+ mRestoreSetDir = new File(mDataDir, Long.toString(token));
+ mRestoreSetIncrementalDir = new File(mRestoreSetDir, INCREMENTAL_DIR);
+ mRestoreSetFullDir = new File(mRestoreSetDir, FULL_DATA_DIR);
return BackupTransport.TRANSPORT_OK;
}
- public String nextRestorePackage() {
+ @Override
+ public RestoreDescription nextRestorePackage() {
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
+
+ boolean found = false;
while (++mRestorePackage < mRestorePackages.length) {
String name = mRestorePackages[mRestorePackage].packageName;
+
+ // If we have key/value data for this package, deliver that
// skip packages where we have a data dir but no actual contents
- String[] contents = (new File(mRestoreDataDir, name)).list();
+ String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
if (contents != null && contents.length > 0) {
- if (DEBUG) Log.v(TAG, " nextRestorePackage() = " + name);
- return name;
+ if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) = " + name);
+ mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
+ found = true;
+ }
+
+ if (!found) {
+ // No key/value data; check for [non-empty] full data
+ File maybeFullData = new File(mRestoreSetFullDir, name);
+ if (maybeFullData.length() > 0) {
+ if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_FULL_STREAM) = " + name);
+ mRestoreType = RestoreDescription.TYPE_FULL_STREAM;
+ found = true;
+ }
+ }
+
+ if (found) {
+ return new RestoreDescription(name, mRestoreType);
}
}
if (DEBUG) Log.v(TAG, " no more packages to restore");
- return "";
+ return RestoreDescription.NO_MORE_PACKAGES;
}
public int getRestoreData(ParcelFileDescriptor outFd) {
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
- File packageDir = new File(mRestoreDataDir, mRestorePackages[mRestorePackage].packageName);
+ if (mRestoreType != RestoreDescription.TYPE_KEY_VALUE) {
+ throw new IllegalStateException("getRestoreData(fd) for non-key/value dataset");
+ }
+ File packageDir = new File(mRestoreSetDir, mRestorePackages[mRestorePackage].packageName);
// The restore set is the concatenation of the individual record blobs,
// each of which is a file in the package's directory. We return the
@@ -463,8 +495,8 @@
// Full restore handling
public int prepareFullRestore(long token, String[] targetPackages) {
- mRestoreDataDir = new File(mDataDir, Long.toString(token));
- mFullRestoreSetDir = new File(mRestoreDataDir, "_full");
+ mRestoreSetDir = new File(mDataDir, Long.toString(token));
+ mFullRestoreSetDir = new File(mRestoreSetDir, FULL_DATA_DIR);
mFullRestorePackages = new HashSet<String>();
if (mFullRestoreSetDir.exists()) {
List<String> pkgs = Arrays.asList(mFullRestoreSetDir.list());
diff --git a/core/java/com/android/internal/policy/IFaceLockInterface.aidl b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
index 017801b..bc1f002 100644
--- a/core/java/com/android/internal/policy/IFaceLockInterface.aidl
+++ b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
@@ -23,6 +23,7 @@
void startUi(IBinder containingWindowToken, int x, int y, int width, int height,
boolean useLiveliness);
void stopUi();
+ void startWithoutUi();
void registerCallback(IFaceLockCallback cb);
void unregisterCallback(IFaceLockCallback cb);
}
diff --git a/core/java/com/android/server/SystemServiceManager.java b/core/java/com/android/server/SystemServiceManager.java
index 87a50a9..fda6479 100644
--- a/core/java/com/android/server/SystemServiceManager.java
+++ b/core/java/com/android/server/SystemServiceManager.java
@@ -50,8 +50,19 @@
* @return The service instance.
*/
@SuppressWarnings("unchecked")
- public SystemService startService(String className) throws ClassNotFoundException {
- return startService((Class<SystemService>) Class.forName(className));
+ public SystemService startService(String className) {
+ final Class<SystemService> serviceClass;
+ try {
+ serviceClass = (Class<SystemService>)Class.forName(className);
+ } catch (ClassNotFoundException ex) {
+ Slog.i(TAG, "Starting " + className);
+ throw new RuntimeException("Failed to create service " + className
+ + ": service class not found, usually indicates that the caller should "
+ + "have called PackageManager.hasSystemFeature() to check whether the "
+ + "feature is available on this device before trying to start the "
+ + "services that implement it", ex);
+ }
+ return startService(serviceClass);
}
/**
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f2b9bac..a7a1faad 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -159,6 +159,7 @@
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
+extern int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
extern int register_android_server_Watchdog(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -1328,6 +1329,7 @@
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
+ REG_JNI(register_android_server_fingerprint_FingerprintService),
REG_JNI(register_android_server_NetworkManagementSocketTagger),
REG_JNI(register_android_server_Watchdog),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index a5964c8..4584c46 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -569,12 +569,11 @@
canvas->drawRectCoords(left, top, right, bottom, *paint);
}
- static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jobject joval,
- jlong paintHandle) {
+ static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jlong paintHandle) {
SkCanvas* canvas = getNativeCanvas(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
- SkRect oval;
- GraphicsJNI::jrectf_to_rect(env, joval, &oval);
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
canvas->drawOval(oval, *paint);
}
@@ -585,13 +584,12 @@
canvas->drawCircle(cx, cy, radius, *paint);
}
- static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jobject joval,
- jfloat startAngle, jfloat sweepAngle,
- jboolean useCenter, jlong paintHandle) {
+ static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, jboolean useCenter,
+ jlong paintHandle) {
SkCanvas* canvas = getNativeCanvas(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
- SkRect oval;
- GraphicsJNI::jrectf_to_rect(env, joval, &oval);
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
canvas->drawArc(oval, startAngle, sweepAngle, useCenter, *paint);
}
@@ -1241,11 +1239,9 @@
{"native_drawLines", "(J[FIIJ)V", (void*) SkCanvasGlue::drawLines},
{"native_drawLine","(JFFFFJ)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
{"native_drawRect","(JFFFFJ)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
- {"native_drawOval","(JLandroid/graphics/RectF;J)V",
- (void*) SkCanvasGlue::drawOval},
+ {"native_drawOval","(JFFFFJ)V", (void*) SkCanvasGlue::drawOval},
{"native_drawCircle","(JFFFJ)V", (void*) SkCanvasGlue::drawCircle},
- {"native_drawArc","(JLandroid/graphics/RectF;FFZJ)V",
- (void*) SkCanvasGlue::drawArc},
+ {"native_drawArc","(JFFFFFFZJ)V", (void*) SkCanvasGlue::drawArc},
{"native_drawRoundRect","(JFFFFFFJ)V",
(void*) SkCanvasGlue::drawRoundRect},
{"native_drawPath","(JJJ)V", (void*) SkCanvasGlue::drawPath},
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 1e40d94..d07b154 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -936,32 +936,62 @@
return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
}
- static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
+ static int breakText(JNIEnv* env, const SkPaint& paint, TypefaceImpl* typeface, const jchar text[],
int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
- SkPaint::TextBufferDirection tbd) {
+ SkPaint::TextBufferDirection textBufferDirection) {
+ size_t measuredCount = 0;
+ float measured = 0;
+
+#ifdef USE_MINIKIN
+ Layout layout;
+ std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface);
+ layout.doLayout(text, 0, count, count, css);
+ float* advances = new float[count];
+ layout.getAdvances(advances);
+ const bool forwardScan = (textBufferDirection == SkPaint::kForward_TextBufferDirection);
+ for (int i = 0; i < count; i++) {
+ // traverse in the given direction
+ int index = forwardScan ? i : (count - i - 1);
+ float width = advances[index];
+ if (measured + width > maxWidth) {
+ break;
+ }
+ // properly handle clusters when scanning backwards
+ if (forwardScan || width != 0.0f) {
+ measuredCount = i + 1;
+ }
+ measured += width;
+ }
+ delete[] advances;
+#else
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
text, 0, count, count, bidiFlags);
if (value == NULL) {
return 0;
}
- SkScalar measured;
- size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1,
- maxWidth, &measured, tbd);
+ SkScalar m;
+ size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1,
+ maxWidth, &m, textBufferDirection);
SkASSERT((bytes & 1) == 0);
+ measuredCount = bytes >> 1;
+ measured = SkScalarToFloat(m);
+#endif
if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
jfloat* array = autoMeasured.ptr();
- array[0] = SkScalarToFloat(measured);
+ array[0] = measured;
}
- return bytes >> 1;
+ return measuredCount;
}
- static jint breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext,
+ static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
- NPE_CHECK_RETURN_ZERO(env, jpaint);
NPE_CHECK_RETURN_ZERO(env, jtext);
+ SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+
SkPaint::TextBufferDirection tbd;
if (count < 0) {
tbd = SkPaint::kBackward_TextBufferDirection;
@@ -976,28 +1006,28 @@
return 0;
}
- SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
const jchar* text = env->GetCharArrayElements(jtext, NULL);
- count = breakText(env, *paint, text + index, count, maxWidth,
+ count = breakText(env, *paint, typeface, text + index, count, maxWidth,
bidiFlags, jmeasuredWidth, tbd);
env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
JNI_ABORT);
return count;
}
- static jint breakTextS(JNIEnv* env, jobject jpaint, jstring jtext,
+ static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
- NPE_CHECK_RETURN_ZERO(env, jpaint);
NPE_CHECK_RETURN_ZERO(env, jtext);
+ SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+
SkPaint::TextBufferDirection tbd = forwards ?
SkPaint::kForward_TextBufferDirection :
SkPaint::kBackward_TextBufferDirection;
- SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
int count = env->GetStringLength(jtext);
const jchar* text = env->GetStringChars(jtext, NULL);
- count = breakText(env, *paint, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
+ count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
env->ReleaseStringChars(jtext, text);
return count;
}
@@ -1108,8 +1138,8 @@
{"native_measureText","([CIII)F", (void*) SkPaintGlue::measureText_CIII},
{"native_measureText","(Ljava/lang/String;I)F", (void*) SkPaintGlue::measureText_StringI},
{"native_measureText","(Ljava/lang/String;III)F", (void*) SkPaintGlue::measureText_StringIII},
- {"native_breakText","([CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
- {"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
+ {"native_breakText","(JJ[CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
+ {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
{"native_getTextWidths","(JJ[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F},
{"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F},
{"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F",
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 420a17f..6ef1d2c 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -2,22 +2,22 @@
**
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
// This file was generated from the C++ include file: SkPath.h
// Any changes made to this file will be discarded by the build.
-// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
// or one of the auxilary file specifications in device/tools/gluemaker.
#include "jni.h"
@@ -92,7 +92,7 @@
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
return obj->isEmpty();
}
-
+
static jboolean isRect(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect) {
SkRect rect;
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
@@ -100,65 +100,66 @@
GraphicsJNI::rect_to_jrectf(rect, env, jrect);
return result;
}
-
+
static void computeBounds(JNIEnv* env, jobject clazz, jlong objHandle, jobject jbounds) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
const SkRect& bounds = obj->getBounds();
GraphicsJNI::rect_to_jrectf(bounds, env, jbounds);
}
-
+
static void incReserve(JNIEnv* env, jobject clazz, jlong objHandle, jint extraPtCount) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->incReserve(extraPtCount);
}
-
+
static void moveTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->moveTo(x, y);
}
-
+
static void rMoveTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->rMoveTo(dx, dy);
}
-
+
static void lineTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->lineTo(x, y);
}
-
+
static void rLineTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->rLineTo(dx, dy);
}
-
+
static void quadTo__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->quadTo(x1, y1, x2, y2);
}
-
+
static void rQuadTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->rQuadTo(dx1, dy1, dx2, dy2);
}
-
+
static void cubicTo__FFFFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->cubicTo(x1, y1, x2, y2, x3, y3);
}
-
+
static void rCubicTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->rCubicTo(x1, y1, x2, y2, x3, y3);
}
-
- static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle, jboolean forceMoveTo) {
+
+ static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
+ jboolean forceMoveTo) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkRect oval_;
- GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
- obj->arcTo(oval_, startAngle, sweepAngle, forceMoveTo);
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
+ obj->arcTo(oval, startAngle, sweepAngle, forceMoveTo);
}
-
+
static void close(JNIEnv* env, jobject clazz, jlong objHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->close();
@@ -185,28 +186,26 @@
obj->addCircle(x, y, radius, dir);
}
- static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle) {
- SkRect oval_;
+ static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle) {
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
- obj->addArc(oval_, startAngle, sweepAngle);
+ obj->addArc(oval, startAngle, sweepAngle);
}
- static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect,
- jfloat rx, jfloat ry, jint dirHandle) {
- SkRect rect;
+ static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloat rx, jfloat ry, jint dirHandle) {
+ SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
- GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
obj->addRoundRect(rect, rx, ry, dir);
}
-
- static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jobject jrect,
- jfloatArray array, jint dirHandle) {
- SkRect rect;
+
+ static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloatArray array, jint dirHandle) {
+ SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
- GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
AutoJavaFloatArray afa(env, array, 8);
#ifdef SK_SCALAR_IS_FLOAT
const float* src = afa.ptr();
@@ -215,32 +214,32 @@
#endif
obj->addRoundRect(rect, src, dir);
}
-
+
static void addPath__PathFF(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jfloat dx, jfloat dy) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
obj->addPath(*src, dx, dy);
}
-
+
static void addPath__Path(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
obj->addPath(*src);
}
-
+
static void addPath__PathMatrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong matrixHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
obj->addPath(*src, *matrix);
}
-
+
static void offset__FFPath(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy, jlong dstHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
obj->offset(dx, dy, dst);
}
-
+
static void offset__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->offset(dx, dy);
@@ -250,14 +249,14 @@
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->setLastPt(dx, dy);
}
-
+
static void transform__MatrixPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle, jlong dstHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
obj->transform(*matrix, dst);
}
-
+
static void transform__Matrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
@@ -487,14 +486,14 @@
{"native_rQuadTo","(JFFFF)V", (void*) SkPathGlue::rQuadTo},
{"native_cubicTo","(JFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF},
{"native_rCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo},
- {"native_arcTo","(JLandroid/graphics/RectF;FFZ)V", (void*) SkPathGlue::arcTo},
+ {"native_arcTo","(JFFFFFFZ)V", (void*) SkPathGlue::arcTo},
{"native_close","(J)V", (void*) SkPathGlue::close},
{"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect},
{"native_addOval","(JFFFFI)V", (void*) SkPathGlue::addOval},
{"native_addCircle","(JFFFI)V", (void*) SkPathGlue::addCircle},
- {"native_addArc","(JLandroid/graphics/RectF;FF)V", (void*) SkPathGlue::addArc},
- {"native_addRoundRect","(JLandroid/graphics/RectF;FFI)V", (void*) SkPathGlue::addRoundRectXY},
- {"native_addRoundRect","(JLandroid/graphics/RectF;[FI)V", (void*) SkPathGlue::addRoundRect8},
+ {"native_addArc","(JFFFFFF)V", (void*) SkPathGlue::addArc},
+ {"native_addRoundRect","(JFFFFFFI)V", (void*) SkPathGlue::addRoundRectXY},
+ {"native_addRoundRect","(JFFFF[FI)V", (void*) SkPathGlue::addRoundRect8},
{"native_addPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF},
{"native_addPath","(JJ)V", (void*) SkPathGlue::addPath__Path},
{"native_addPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix},
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 86207f0..87ee618 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -174,21 +174,21 @@
ssize_t pss = memtrack_proc_graphics_pss(p);
if (pss < 0) {
- ALOGW("failed to get graphics pss: %d", pss);
+ ALOGW("failed to get graphics pss: %zd", pss);
return pss;
}
graphics_mem->graphics = pss / 1024;
pss = memtrack_proc_gl_pss(p);
if (pss < 0) {
- ALOGW("failed to get gl pss: %d", pss);
+ ALOGW("failed to get gl pss: %zd", pss);
return pss;
}
graphics_mem->gl = pss / 1024;
pss = memtrack_proc_other_pss(p);
if (pss < 0) {
- ALOGW("failed to get other pss: %d", pss);
+ ALOGW("failed to get other pss: %zd", pss);
return pss;
}
graphics_mem->other = pss / 1024;
@@ -231,9 +231,9 @@
unsigned referenced = 0;
unsigned temp;
- unsigned long int start;
- unsigned long int end = 0;
- unsigned long int prevEnd = 0;
+ uint64_t start;
+ uint64_t end = 0;
+ uint64_t prevEnd = 0;
char* name;
int name_pos;
@@ -255,7 +255,7 @@
if (len < 1) return;
line[--len] = 0;
- if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
+ if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
skip = true;
} else {
while (isspace(line[name_pos])) {
@@ -371,7 +371,7 @@
referenced = temp;
} else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
swapped_out = temp;
- } else if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') {
+ } else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) {
// looks like a new mapping
// example: "10000000-10001000 ---p 10000000 00:00 0"
break;
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index f8a1fd9..ad36843c 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -20,30 +20,10 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
#include <utils/Log.h>
-namespace android {
-
-static struct {
- jclass clazz;
- jmethodID notify;
-} gFingerprintManagerClassInfo;
-
-static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
- return -1; // TODO
-}
-
-static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
- return -1; // TODO
-}
-
-// ----------------------------------------------------------------------------
-
-static const JNINativeMethod g_methods[] = {
- { "nativeEnroll", "(I)I", (void*)nativeEnroll },
- { "nativeRemove", "(I)I", (void*)nativeRemove },
-};
-
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className); \
@@ -61,13 +41,174 @@
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-int register_android_server_FingerprintManager(JNIEnv* env) {
- FIND_CLASS(gFingerprintManagerClassInfo.clazz,
- "android/service/fingerprint/FingerprintManager");
- GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz,
- "notify", "(III)V");
- return AndroidRuntime::registerNativeMethods(
- env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods));
+namespace android {
+
+static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(1, 0);
+
+static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService";
+static struct {
+ jclass clazz;
+ jmethodID notify;
+ jobject callbackObject;
+} gFingerprintServiceClassInfo;
+
+static struct {
+ fingerprint_module_t const* module;
+ fingerprint_device_t *device;
+} gContext;
+
+// TODO: remove after driver update to use new HAL
+fingerprint_msg_type_t hackTilFpDriverUpdate(fingerprint_msg_type_t t) {
+ switch(static_cast<int>(t)) {
+ case 1: return FINGERPRINT_PROCESSED;
+ case 2: return FINGERPRINT_TEMPLATE_ENROLLING;
+ default: return t;
+ }
+}
+
+// Called by the HAL to notify us of fingerprint events
+static void hal_notify_callback(fingerprint_msg_t msg) {
+ uint32_t arg1 = 0;
+ uint32_t arg2 = 0;
+ uint32_t arg3 = 0; // TODO
+ msg.type = hackTilFpDriverUpdate(msg.type);
+ switch (msg.type) {
+ case FINGERPRINT_ERROR:
+ arg1 = msg.data.error;
+ break;
+ case FINGERPRINT_ACQUIRED:
+ arg1 = msg.data.acquired.acquired_info;
+ break;
+ case FINGERPRINT_PROCESSED:
+ arg1 = msg.data.processed.id;
+ break;
+ case FINGERPRINT_TEMPLATE_ENROLLING:
+ arg1 = msg.data.enroll.id;
+ arg2 = msg.data.enroll.samples_remaining;
+ arg3 = msg.data.enroll.data_collected_bmp;
+ break;
+ case FINGERPRINT_TEMPLATE_REMOVED:
+ arg1 = msg.data.removed.id;
+ break;
+ default:
+ ALOGE("fingerprint: invalid msg: %d", msg.type);
+ return;
+ }
+ //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
+
+ // TODO: fix gross hack to attach JNI to calling thread
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (env == NULL) {
+ JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
+ JavaVM* vm = AndroidRuntime::getJavaVM();
+ int result = vm->AttachCurrentThread(&env, (void*) &args);
+ if (result != JNI_OK) {
+ ALOGE("Can't call JNI method: attach failed: %#x", result);
+ return;
+ }
+ }
+ env->CallVoidMethod(gFingerprintServiceClassInfo.callbackObject,
+ gFingerprintServiceClassInfo.notify, msg.type, arg1, arg2);
+}
+
+static void nativeInit(JNIEnv *env, jobject clazz, jobject callbackObj) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeInit()\n");
+ FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
+ GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz,
+ "notify", "(III)V");
+ gFingerprintServiceClassInfo.callbackObject = env->NewGlobalRef(callbackObj);
+}
+
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
+ int ret = gContext.device->enroll(gContext.device, timeout);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnrollCancel()\n");
+ int ret = gContext.device->enroll_cancel(gContext.device);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
+ int ret = gContext.device->remove(gContext.device, fingerprintId);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeOpenHal(JNIEnv* env, jobject clazz) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
+ int err;
+ const hw_module_t *hw_module = NULL;
+ if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
+ ALOGE("Can't open fingerprint HW Module, error: %d", err);
+ return 0;
+ }
+ if (NULL == hw_module) {
+ ALOGE("No valid fingerprint module");
+ return 0;
+ }
+
+ gContext.module = reinterpret_cast<const fingerprint_module_t*>(hw_module);
+
+ if (gContext.module->common.methods->open == NULL) {
+ ALOGE("No valid open method");
+ return 0;
+ }
+
+ hw_device_t *device = NULL;
+
+ if (0 != (err = gContext.module->common.methods->open(hw_module, NULL, &device))) {
+ ALOGE("Can't open fingerprint methods, error: %d", err);
+ return 0;
+ }
+
+ if (kVersion != device->version) {
+ ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
+ // return 0; // FIXME
+ }
+
+ gContext.device = reinterpret_cast<fingerprint_device_t*>(device);
+ err = gContext.device->set_notify(gContext.device, hal_notify_callback);
+ if (err < 0) {
+ ALOGE("Failed in call to set_notify(), err=%d", err);
+ return 0;
+ }
+
+ // Sanity check - remove
+ if (gContext.device->notify != hal_notify_callback) {
+ ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback);
+ }
+
+ ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
+ return reinterpret_cast<jlong>(gContext.device);
+}
+
+static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
+ return -ENOSYS; // TODO
+}
+
+// ----------------------------------------------------------------------------
+
+// TODO: clean up void methods
+static const JNINativeMethod g_methods[] = {
+ { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+ { "nativeEnrollCancel", "()I", (void*)nativeEnroll },
+ { "nativeRemove", "(I)I", (void*)nativeRemove },
+ { "nativeOpenHal", "()I", (void*)nativeOpenHal },
+ { "nativeCloseHal", "()I", (void*)nativeCloseHal },
+ { "nativeInit", "(Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit }
+};
+
+int register_android_server_fingerprint_FingerprintService(JNIEnv* env) {
+ FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
+ GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz, "notify",
+ "(III)V");
+ int result = AndroidRuntime::registerNativeMethods(
+ env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
+ ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
+ return result;
}
} // namespace android
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c0d5221..cfc8eb8 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -61,6 +61,8 @@
jfieldID xDpi;
jfieldID yDpi;
jfieldID secure;
+ jfieldID appVsyncOffsetNanos;
+ jfieldID presentationDeadlineNanos;
} gPhysicalDisplayInfoClassInfo;
static struct {
@@ -392,6 +394,10 @@
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
+ env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos,
+ info.appVsyncOffset);
+ env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos,
+ info.presentationDeadline);
env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
env->DeleteLocalRef(infoObj);
}
@@ -648,6 +654,10 @@
gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
+ gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = env->GetFieldID(clazz,
+ "appVsyncOffsetNanos", "J");
+ gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = env->GetFieldID(clazz,
+ "presentationDeadlineNanos", "J");
jclass rectClazz = env->FindClass("android/graphics/Rect");
gRectClassInfo.bottom = env->GetFieldID(rectClazz, "bottom", "I");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index edca101..8b5dff0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -657,6 +657,13 @@
android:label="@string/permlab_addVoicemail"
android:description="@string/permdesc_addVoicemail" />
+ <!-- Allows an application to read all the voicemails in the system. -->
+ <permission android:name="com.android.voicemail.permission.READ_ALL_VOICEMAIL"
+ android:permissionGroup="android.permission-group.VOICEMAIL"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_readAllVoicemail"
+ android:description="@string/permdesc_readAllVoicemail" />
+
<!-- =============================================== -->
<!-- Permissions for enabling accessibility features -->
<!-- =============================================== -->
@@ -2928,6 +2935,12 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+ <service
+ android:name="com.android.server.pm.BackgroundDexOptService"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE">
+ </service>
+
</application>
</manifest>
diff --git a/core/res/res/drawable-hdpi/ic_corp_badge.png b/core/res/res/drawable-hdpi/ic_corp_badge.png
new file mode 100644
index 0000000..c79ce92
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_corp_badge.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_corp_icon_badge.png b/core/res/res/drawable-hdpi/ic_corp_icon_badge.png
new file mode 100644
index 0000000..0059e09
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_corp_icon_badge.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_corp_badge.png b/core/res/res/drawable-mdpi/ic_corp_badge.png
new file mode 100644
index 0000000..c1447fe
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_corp_badge.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_corp_icon_badge.png b/core/res/res/drawable-mdpi/ic_corp_icon_badge.png
new file mode 100644
index 0000000..5ff8c5d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_corp_icon_badge.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_corp_badge.png b/core/res/res/drawable-xhdpi/ic_corp_badge.png
new file mode 100644
index 0000000..2d3d748
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_corp_badge.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_corp_icon_badge.png b/core/res/res/drawable-xhdpi/ic_corp_icon_badge.png
new file mode 100644
index 0000000..dc5716d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_corp_icon_badge.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_corp_badge.png b/core/res/res/drawable-xxhdpi/ic_corp_badge.png
new file mode 100644
index 0000000..430e63b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_corp_badge.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_corp_icon_badge.png b/core/res/res/drawable-xxhdpi/ic_corp_icon_badge.png
new file mode 100644
index 0000000..cc00dd8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_corp_icon_badge.png
Binary files differ
diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml
deleted file mode 100644
index 5325712..0000000
--- a/core/res/res/drawable/ic_corp_badge.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="19.0dp"
- android:height="19.0dp"/>
-
- <viewport
- android:viewportWidth="19.0"
- android:viewportHeight="19.0"/>
-
- <path
- android:pathData="M9.5,9.5m-9.5,0.0a9.5,9.5 0.0,1.0 1.0,19.0 0.0a9.5,9.5 0.0,1.0 1.0,-19.0 0.0"
- android:fill="#FF5722"/>
- <path
- android:pathData="M12.667,7.125l-1.583,0.0L11.084,6.333l-0.792,-0.792L8.708,5.5410004L7.917,6.333l0.0,0.792L6.333,7.125c-0.438,0.0 -0.788,0.354 -0.788,0.792l-0.004,4.354c0.0,0.438 0.354,0.792 0.792,0.792l6.333,0.0c0.438,0.0 0.792,-0.354 0.792,-0.792L13.458,7.917C13.458,7.479 13.104,7.125 12.667,7.125zM10.094,10.687L8.906,10.687L8.906,9.5l1.188,0.0L10.094,10.687zM10.292,7.125L8.708,7.125L8.708,6.333l1.583,0.0L10.291,7.125z"
- android:fill="#FFFFFF"/>
- <path
- android:pathData="M4.75,4.75 h9.5 v9.5 h-9.5z"
- android:fill="#00000000"/>
-</vector>
diff --git a/core/res/res/drawable/ic_corp_icon_badge.xml b/core/res/res/drawable/ic_corp_icon_badge.xml
deleted file mode 100644
index 7bfab4c..0000000
--- a/core/res/res/drawable/ic_corp_icon_badge.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64.0dp"
- android:height="64.0dp"/>
-
- <viewport
- android:viewportWidth="64.0"
- android:viewportHeight="64.0"/>
-
- <path
- android:fill="#FF000000"
- android:pathData="M49.062,50.0m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"/>
- <path
- android:fill="#FF000000"
- android:pathData="M49.0,49.5m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"/>
- <path
- android:pathData="M49.0,49.0m-14.0,0.0a14.0,14.0 0.0,1.0 1.0,28.0 0.0a14.0,14.0 0.0,1.0 1.0,-28.0 0.0"
- android:fill="#FF5722"/>
- <path
- android:pathData="M53.667,45.5l-2.333,0.0l0.0,-1.167l-1.167,-1.167l-2.333,0.0l-1.167,1.167L46.667,45.5l-2.333,0.0c-0.645,0.0 -1.161,0.522 -1.161,1.167l-0.006,6.417c0.0,0.645 0.522,1.167 1.167,1.167l9.333,0.0c0.645,0.0 1.167,-0.522 1.167,-1.167l0.0,-6.417C54.833,46.022 54.311,45.5 53.667,45.5zM49.875,50.75l-1.75,0.0L48.125,49.0l1.75,0.0L49.875,50.75zM50.167,45.5l-2.333,0.0l0.0,-1.167l2.333,0.0L50.167,45.5z"
- android:fill="#FFFFFF"/>
- <path
- android:pathData="M42.0,42.0 h14.0 v14.0 h-14.0z"
- android:fill="#00000000"/>
-</vector>
diff --git a/core/res/res/drawable/view_accessibility_focused.xml b/core/res/res/drawable/view_accessibility_focused.xml
index 0da9a81..68e3f1e 100644
--- a/core/res/res/drawable/view_accessibility_focused.xml
+++ b/core/res/res/drawable/view_accessibility_focused.xml
@@ -17,9 +17,11 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke
- android:width="2dp"
- android:color="@color/accessibility_focus_highlight" />
+ android:width="4dp"
+ android:color="@color/accessibility_focus_highlight"
+ android:dashWidth="4dp"
+ android:dashGap="2dp" />
- <corners android:radius="2dp"/>
+ <corners android:radius="2dp" />
</shape>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 21fd37d..72b0909 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1362,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Laat \'n program toe om vir veranderinge in vertrouenstaat te luister."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Voorsien \'n vertroude agent."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Laat \'n program toe om \'n vertroude agent te voorsien."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Verbind met \'n vertrouensagentdiens"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Laat \'n program toe om met \'n vertrouensagentdiens te verbind."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Tree in wisselwerking met opdatering- en terugstellingstelsel"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index abeadfa..da89136 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"መተግበሪያው በተአማኒነት ሁኔታ ውስጥ ለውጦችን እንዲያዳምጥ ይፈቅዳል።"</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"የመታመን ወኪል ያቅርቡ።"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"አንድ መተግበሪያ የመታመን ወኪል እንዲያቀርብ ይፈቅድለታል።"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"የእምነት ወኪል ቅንብሮች ምናሌን አስጀምር።"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"አንድ መተግበሪያ የእምነት ወኪል ባህሪ የሚቀይር እንቅስቃሴ እንዲያስጀምር ያስችለዋል።"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ለተአማኒነት ወኪል አገልግሎት ተገዢ አድርግ"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ለመተግበሪያን የተአማኒነት ወኪል አገልግሎትን እንዲያከብር ይፈቅዳል።"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"ከዝማኔዎች እና ከመልሶ ማግኛ ስርዓቶች ጋር ይገናኙ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index aa47774..626858f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"للسماح للتطبيق بالتعرف على التغييرات في حالة الاعتماد."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"توفير وكيل معتمد."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"للسماح لأحد التطبيقات بتوفير وكيل معتمد."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"تشغيل قائمة إعدادات الوكيل المعتمد."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"للسماح لأحد التطبيقات بتشغيل نشاط يؤدي إلى تغيير سلوك الوكيل المعتمد."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"الالتزام بخدمة الوكيل المعتمد"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"للسماح لأحد التطبيقات بالالتزام بخدمة الوكيل المعتمد."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"التفاعل مع نظام التحديث والاسترداد"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index a8ceac6..ca71ce3 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Лични приложения"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Служебен под Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Услуги, които ви струват пари"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Извършват неща, които могат да ви струват пари."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Вашите съобщения"</string>
@@ -1363,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Разрешава на приложението да следи за промени в състоянието на надеждност."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Предоставяне на trust agent."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Разрешава на приложението да предоставя trust agent."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Обвързване с услуга за trust agents"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Разрешава на приложението да се обвърже с услуга за trust agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействие със системата за актуализации и възстановяване"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f6aaf73d..e1eed49 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1362,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet que una aplicació escolti els canvis en l\'estat de confiança."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Proporcionar un agent de confiança"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permet que una aplicació proporcioni un agent de confiança."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enllaçar amb el servei d\'un agent de confiança"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet que una aplicació es vinculi amb el servei d\'un agent de confiança."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interacciona amb el sistema de recuperació i amb les actualitzacions"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index d18c107..cf06dc1 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1362,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikaci naslouchat změnám ve stavu důvěryhodnosti."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Poskytování zástupce důvěryhodnosti"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Umožňuje aplikaci poskytnout zástupce důvěryhodnosti."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vázat se na službu zástupce důvěryhodnosti"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikaci vázat se na službu zástupce důvěryhodnosti."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakce se systémem aktualizací a obnovení"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 8695451..0aa2a36 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillader, at en applikation registrerer ændringer i trust-tilstand."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Angiv en tillidsagent."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Tillader, at en applikation angiver en tillidsagent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Åbn indstillingsmenuen for tillidsagenten"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Giver en applikation tilladelse til at starte en aktivitet, som ændrer adfærden for tillidsagenten."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Knytte sig til en trust agent-tjeneste"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillader, at en applikation knytter sig til en trust agent-tjeneste."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interager med opdaterings- og gendannelsessystemet"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index bffbd1e..d557d37 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Ermöglicht einer App die Überwachungen von Änderungen des Trust-Status"</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Trust Agent bereitstellen"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ermöglich die Bereitstellung eines Trust Agents durch eine App"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Einstellungsmenü des Trust Agents starten"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Ermöglicht einer App das Starten einer Aktivität, die das Verhalten des Trust Agents ändert"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"An Trust Agent-Service anbinden"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ermöglicht einer App die Anbindung an einen Trust Agent-Service"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Mit Update- und Wiederherstellungssystem interagieren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 59e9085..8205c60 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Επιτρέπει σε μια εφαρμογή να αντιλαμβάνεται τις αλλαγές στην κατάσταση εμπιστοσύνης."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Παράσχετε έναν αξιόπιστο αντιπρόσωπο."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Επιτρέπει σε μια εφαρμογή να προσφέρει έναν αξιόπιστο αντιπρόσωπο."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Εκκίνηση μενού ρυθμίσεων αξιόπιστου αντιπροσώπου."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Επιτρέπει σε μια εφαρμογή να εκκινεί μια ενέργεια που αλλάζει τη συμπεριφορά του αξιόπιστου αντιπροσώπου."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Σύνδεση σε υπηρεσία trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Επιτρέπει σε μια εφαρμογή να συνδεθεί σε μια υπηρεσία trust agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Αλληλεπίδραση με το σύστημα ενημέρωσης και ανάκτησης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c7d6149..a0c35c8 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Provide a trust agent."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Allows an application to provide a trust agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Lunch trust agent settings menu."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Allows an application to lunch an activity that changes the trust agent behaviour."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index c7d6149..a0c35c8 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Provide a trust agent."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Allows an application to provide a trust agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Lunch trust agent settings menu."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Allows an application to lunch an activity that changes the trust agent behaviour."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 8db1114..b6a7667 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Proporcionar un agente de confianza"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que una aplicación proporcione un agente de confianza."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Iniciar menú de configuración de agente de confianza"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Permite que una aplicación inicie una actividad que modifica el comportamiento del agente de confianza."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular con un servicio de agente de confianza"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que una aplicación se vincule con un servicio de agente de confianza."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interaccionar con el sistema de recuperación y las actualizaciones"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 5ad1cd3..1dcbf62 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Proporcionar un agente de confianza."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que una aplicación proporcione un agente de confianza."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Abre el menú de ajustes del agente de confianza."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Permite que una aplicación inicie una actividad que cambie el comportamiento del agente de confianza."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enlazar con un servicio de agente de confianza"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite a una aplicación enlazar con un servicio de agente de confianza."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interactuar con el sistema de recuperación y las actualizaciones"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 7a4659b..60d036e 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Lubab rakendusel tuvastada muudatusi usaldusväärses olekus."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Usaldusväärse agendi esitamine."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Võimaldab rakendusel esitada usaldusväärset agenti."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Käivita usaldusväärse agendi seadete menüü."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Võimaldab rakendusel käivitada tegevuse, mis muudab usaldusväärse agendi käitumist."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Usaldusväärse agendi teenusega sidumine"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lubab rakendusel ennast siduda usaldusväärse agendi teenusega."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Suhtlemine värskenduse ja taastesüsteemiga"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e9628ec..b4727bb 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1362,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"به یک برنامه کاربردی برای گوش دادن به تغییرات در trust اجازه میدهد."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"یک عامل مورد اعتماد فراهم میآورد."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"به برنامه امکان میدهد یک عامل مورد اعتماد فراهم آورد."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"اتصال به یک سرویس trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"به یک برنامه کاربردی برای اتصال به یک سرویس trust agent اجازه میدهد."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"تعامل با سیستم بهروزرسانی و بازیابی"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 09f1f45..02c6da4 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1363,6 +1363,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Antaa sovelluksen seurata luottamuksen tilamuutoksia."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Luotettavan tahon tarjoaminen"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Antaa sovelluksen tarjota luotettavan tahon."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Luotettavaan tahoon sitoutuminen"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Antaa sovelluksen sitoutua luotettavaan tahoon."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Vuorovaikutus päivitys- ja palautusjärjestelmän kanssa"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 5982bca..b1292b3 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Applications personnelles"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android pour les activités professionnelles"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Effectuer des opérations payantes"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
@@ -1363,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet à une application de détecter les modifications de l\'état de confiance."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fournir un agent de confiance."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permet à une application de fournir un agent de confiance."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Lier à un service d\'agent de confiance"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet à une application de se lier à un service d\'agent de confiance."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 89ef90c..f511df0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Applications personnelles"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Effectuer des opérations payantes"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
@@ -1363,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permettre à une application de détecter les modifications de l\'état de confiance."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fournir un agent de confiance"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permettre à une application de fournir un agent de confiance"</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"S\'associer à un service d\'agent de confiance"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permettre à une application de s\'associer à un service d\'agent de confiance."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 056f63f..470ec41 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"किसी एप्लिकेशन को ट्रस्ट स्थिति के बदलावों को सुनने की अनुमति देती है."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"विश्वसनीय एजेंट प्रदान करें."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"एप्लिकेशन को विश्वसनीय एजेंट प्रदान करने देती है."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"विश्वस्त एजेंट सेटिंग मेनू लॉन्च करें."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"एप्लिकेशन को ऐसी गतिविधि लॉन्च करने की अनुमति मिलती है जो विश्वस्त एजेंट के व्यवहार में बदलाव लाती है."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ट्रस्ट एजेंट सेवा से आबद्ध करना"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"किसी एप्लिकेशन को ट्रस्ट एजेंट सेवा से आबद्ध करने की अनुमति देती है."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"अपडेट और पुनर्प्राप्ति सिस्टम के साथ सहभागिता करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 8dbe791..7dc8e19 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Osobne aplikacije"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android za posao"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Usluge koje se plaćaju"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Radite stvari koje će uzrokovati novčane troškove."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše poruke"</string>
@@ -1363,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Omogućuje aplikaciji praćenje promjena pouzdanog stanja."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Pružanje agenta za pouzdanost."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Omogućuje aplikaciji pružanje agenta za pouzdanost."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezivanje s uslugom pouzdanog predstavnika"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Omogućuje aplikaciji povezivanje s uslugom pouzdanog predstavnika."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakcija s ažuriranjem i sustavom za oporavak"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index cbe36be..2582737 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Lehetővé teszi, hogy az alkalmazás figyelje a trust-állapot változásait."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Trust agent szoftver megadása"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Lehetővé teszi, hogy az alkalmazás megadjon egy trust agent szoftvert."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Trust agent szoftver beállításmenüjének indítása."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Lehetővé teszi az alkalmazások számára olyan tevékenységek indítását, amelyek megváltoztatják a trust agent szoftver viselkedését."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Csatlakozás egy trust agent szolgáltatáshoz"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lehetővé teszi, hogy az alkalmazás egy trust agent szolgáltatáshoz csatlakozzon."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Kapcsolatfelvétel a frissítési és helyreállítási rendszerrel"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 17779b7..f0bee2b 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Անձնական ծրագրեր"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Ծառայություններ, որոնց համար կգանձվեք"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Կատարել գործողություններ, որի դիմաց ձեր հաշվից գումար կծախսվի:"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ձեր հաղորդագրությունները"</string>
@@ -401,10 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Թույլ է տալիս սեփականատիրոջը միանալ պաստառի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"կապվել ձայնային փոխազդիչին"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Թույլ է տալիս սեփականատիրոջը միանալ ձայնային փոխազդիչի բազային միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
- <!-- no translation found for permlab_manageVoiceKeyphrases (1252285102392793548) -->
- <skip />
- <!-- no translation found for permdesc_manageVoiceKeyphrases (8476560722907530008) -->
- <skip />
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"կառավարել ձայնային բանալի բառակապակցությունները"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Սեփականատիրոջը թույլ է տալիս կառավարել բանալի բառակապակցությունները՝ ձայնային թեժ բառերի հայտնաբերման համար: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"միանալ հեռակա էկրանին"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Թույլ է տալիս սեփականատիրոջը միանալ հեռակա էկրանի վերին մակարդակի ինտերֆեյսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"միանալ վիջեթ ծառայությանը"</string>
@@ -1365,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Ծրագրին թույլ է տալիս լսել վստահության կարգավիճակի փոփոխությունները:"</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Տրամադրել վստահելի գործակալ:"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ծրագրին թույլ է տալիս տրամադրել վստահելի գործակալ:"</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Կապվել վստահելի գործակալի ծառայությանը"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ծրագրին թույլ է տալիս կապվել վստահելի գործակալի ծառայությանը:"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Փոխազդել թարմացման և վերականգնման համակարգի հետ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 2fb9f8a..9dca8a5 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Aplikasi pribadi"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Layanan berbayar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Lakukan hal yang dapat dikenai biaya."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Pesan Anda"</string>
@@ -1363,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Mengizinkan aplikasi mendengarkan perubahan dalam status kepercayaan."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Berikan agen tepercaya."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Memungkinkan aplikasi memberikan agen tepercaya."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Luncurkan menu setelan agen tepercaya."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Memungkinkan aplikasi meluncurkan aktivitas yang mengubah perilaku agen tepercaya."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Ikat ke layanan agen kepercayaan"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Mengizinkan aplikasi mengikat ke layanan agen kepercayaan."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan sistem pemulihan dan pembaruan"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 8a9ff58..0ea6f6e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Consente a un\'applicazione di rilevare le modifiche nello stato trust."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Indica un trust agent."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Consente a un\'applicazione di indicare un trust agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Avvio del menu di impostazioni del trust agent."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Consente a un\'applicazione di avviare un\'attività che modifica il comportamento del trust agent."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associazione a un servizio trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Consente a un\'applicazione di associarsi a un servizio trust agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interazione con il sistema di ripristino e aggiornamento"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8de9971..19fb05a 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"מאפשר לאפליקציה לחפש שינויים במצב אמון."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"ציון סוכן אמון."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"מאפשר לאפליקציה לספק סוכן אמון."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"הפעלת תפריט ההגדרות של סוכן האמון."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"מאפשר לאפליקציה להתחיל פעילות המשנה את ההתנהגות של סוכן האמון."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"איגוד אל שירות סוכן אמון"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"מאפשר לאפליקציה לאגוד אל שירות סוכן אמון."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"אינטראקציה עם מערכת שחזור ועדכונים"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 3fde38a..6ba99bf 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
<string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
<string name="user_owner_label" msgid="6465364741001216388">"プライベートアプリ"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"料金の発生するサービス"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"料金発生の可能性がある操作を実行します。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"送受信したメッセージ"</string>
@@ -1363,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"信頼状態の変更をリッスンすることをアプリに許可します。"</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"信頼できるエージェントの提供"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"信頼できるエージェントの提供をアプリに許可します。"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"信頼できるエージェントの設定メニューの起動"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"信頼できるエージェントの動作を変更するアクティビティを開始することをアプリに許可します。"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"信頼できるエージェントサービスへのバインド"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"信頼できるエージェントサービスにバインドすることをアプリに許可します。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"アップデートと回復システムへのアクセス"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 01a7194..879d00f 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
<string name="user_owner_label" msgid="6465364741001216388">"პერსონალური აპები"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android სამსახურისთვის"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"სერვისები, რომელშიც ფულის გადახდა გიწევთ"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ისეთი აქტივობების განხორციელება, რომლებშიც ფულის გადახდა მოგიწევთ."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"თქვენი შეტყობინებები"</string>
@@ -401,10 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"მფლობელს შეეძლება ფონის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ხმის ინტერაქტორთან შეკავშირება"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"მფლობელს შეეძლება შეკავშირდეს ხმის ინტერაქციის სერვისების ზედა დონის ინტერფეისთან. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დასჭირდეს."</string>
- <!-- no translation found for permlab_manageVoiceKeyphrases (1252285102392793548) -->
- <skip />
- <!-- no translation found for permdesc_manageVoiceKeyphrases (8476560722907530008) -->
- <skip />
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ხმოვანი საიდუმლო ფრაზების მართვა"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"საშუალებას აძლევს მფლობელს მართოს საიდუმლო ფრაზები ხმოვანი ჯადოსნური სიტყვის ამოცნობისათვის. ეს ჩვეულებრივ აპებს არ უნდა დაჭირდეს."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"დისტანციურ მონიტორზე მიბმა"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"მფლობელს შეეძლება მიებას დისტანციურ მონიტორის ზედა დონის ინტერფეისს. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ვიჯეტ სერვისთან დაკავშირება"</string>
@@ -1365,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"საშუალებას აძლევს აპლიკაციას მოუსმინოს ცვლილებებს სანდო მდგომარეობაში."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"სანდო აგენტის წარმოდგენა."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"საშუალებას აძლევს აპლიკაციას წარმოადგინოს სანდო აგენტი."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"სანდო აგენტის სერვისზე მიმაგრება."</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"საშუალებას აძლევს აპლიკაციას მიემაგროს სანდო აგენტის სერვისს."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"განახლებასთან და აღდგენის სისტემასთან ინტერაქცია"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 62b2e8a..daf004c 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"ឲ្យកម្មវិធីស្ដាប់ការផ្លាស់ប្ដូរក្នុងស្ថានភាពដែលទុកចិត្ត។"</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"ផ្ដល់ភ្នាក់ងារដែលទុកចិត្ត។"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"ឲ្យកម្មវិធីផ្ដល់ភ្នាក់ងារដែលទុកចិត្ត។"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"ចាប់ផ្ដើមម៉ឺនុយការកំណត់ភ្នាក់ងារជឿទុកចិត្ត។"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"អនុញ្ញាតឲ្យកម្មវិធីចាប់ផ្ដើមសកម្មដែលផ្លាស់ប្ដូរឥរិយាបថភ្នាក់ងារជឿទុកចិត្ត។"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ភ្ជាប់ទៅសេវាកម្មភ្នាក់ងារដែលទុកចិត្ត"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ឲ្យកម្មវិធីភ្ជាប់សេវាកម្មភ្នាក់ងារដែលទុកចិត្ត។"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"អន្តរកម្មជាមួយបច្ចុប្បន្នភាព និងប្រព័ន្ធសង្គ្រោះ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 88327ca..43d1b25 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
<string name="user_owner_label" msgid="6465364741001216388">"개인 앱"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"요금이 부과되는 서비스"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"요금이 부과될 수 있는 작업을 수행할 수 있도록 합니다."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"메시지"</string>
@@ -1363,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"애플리케이션이 Trust 상태에서의 변경사항을 수신할 수 있도록 허용합니다."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Trust Agent 제공"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"애플리케이션이 Trust Agent를 제공할 수 있도록 허용합니다."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Trust Agent 서비스에 연결"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"애플리케이션이 Trust Agent 서비스에 바인딩할 수 있도록 허용합니다."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"업데이트 및 복구 시스템과 상호작용"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 44f5e0d..e386a24 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນຕິດຕາມການປ່ຽນແປງໃນສະຖານະການເຊື່ອຖື."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"ລະບຸເອເຈນທີ່ເຊື່ອຖືໄດ້."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນລະບຸເອເຈນທີ່ເຊື່ອຖືໄດ້."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"ເປີດເມນູການຕັ້ງຄ່າເອເຈັນທີ່ເຊື່ອຖືໄດ້."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນເປີດການເຄື່ອນໄຫວທີ່ປ່ຽນແປງພຶດຕິກຳຂອງເອເຈັນທີ່ເຊື່ອຖືໄດ້."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ເຊື່ອມໂຍງຫາບໍລິການຕົວແທນການເຊື່ອຖື"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນເຊື່ອມໂຍງກັບບໍລິການຕົວແທນທີ່ເຊື່ອຖືໄດ້."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"ຕິດຕໍ່ກັບລະບົບອັບເດດ ແລະລະບົບກູ້ຂໍ້ມູນ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 09fbdfb..be7e571 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Programai leidžiama atsižvelgti į patikimos būsenos pakeitimus."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Teikti patikimos priemonės paslaugą."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Programai leidžiama teikti patikimos priemonės paslaugą."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Paleisti patikimo atstovo nustatymų meniu."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Leidžiama programai paleisti veiklą, keičiančią patikimo atstovo elgseną."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Susisaistyti su „trust agent“ paslauga"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Programai leidžiama susisaistyti su „trust agent“ paslauga."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Sąveikauti su naujiniu ir atkūrimo sistema"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 2cb5735..b421da4 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Ļauj lietojumprogrammai klausīties uzticamības statusa izmaiņas."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Nodrošināt uzticamības pārbaudes programmu"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ļauj lietojumprogrammai nodrošināt uzticamības pārbaudes programmu."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Palaist uzticamības pārbaudes programmas iestatījumu izvēlni."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Ļauj lietojumprogrammai palaist darbību, kas maina uzticamības pārbaudes programmas rīcību."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Izveidot savienojumu ar uzticamības pārbaudes pakalpojumu"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ļauj lietojumprogrammai izveidot savienojumu ar uzticamības pārbaudes pakalpojumu."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Mijiedarbošanās ar atjauninājumu un atkopšanas sistēmu"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index b030060..803128f 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Итгэмжлэлд орж буй өөрчлөлтийг мэдэх боломжийг аппликешнд олгоно."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Итгэмжлэгдсэн төлөөлөгч нийлүүлэх"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Аппликешнд итгэмжлэгдсэн төлөөлөгч нийлүүлэх боломж олгоно."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Итгэмжлэгдсэн агентын тохиргоо цэсийг эхлүүлэх."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Аппликешнд итгэмжлэгдсэн агентын авирыг өөрчлөх боломжтой үйлдлийг эхлүүлэхийг зөвшөөрнө."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Итгэмжлэгдсэн төлөөлөгчийн үйлчилгээтэй холбогдох"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Аппликешнд итгэмжлэгдсэн төлөөлөгчтэй холбогдох боломж олгоно."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Шинэчлэлт болон сэргээх системтэй харилцах"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 9ad8f37..1d1a75b 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -401,10 +401,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi kertas dinding. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"terikat kepada interaksi suara"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan interaksi suara. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <!-- no translation found for permlab_manageVoiceKeyphrases (1252285102392793548) -->
- <skip />
- <!-- no translation found for permdesc_manageVoiceKeyphrases (8476560722907530008) -->
- <skip />
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"urus frasa kunci suara"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Membenarkan pemegang menguruskan frasa kunci untuk pengesahan sebutan laluan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"terikat kepada paparan jauh"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi paparan jauh. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"terikat kepada perkhidmatan widget"</string>
@@ -1365,6 +1363,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Membenarkan aplikasi mendengar perubahan dalam keadaan amanah."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Sediakan ejen amanah."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Membenarkan aplikasi menyediakan ejen amanah."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Mengikat kepada perkhidmatan ejen amanah"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Membenarkan aplikasi terikat kepada perkhidmatan ejen amanah."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan kemas kini dan sistem pemulihan"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 1ae5c5e..31fa11d 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Personlige apper"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Betaltjenester"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gjøre ting som kan koste deg penger."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Meldinger"</string>
@@ -1363,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Gir appen tillatelse til å oppdage endringer i tillitsstatusen."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Angivelse av en pålitelig agent."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Tillater appen å angi en pålitelig agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Start innstillingsmenyen til tillitsagenten."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Tillater apper å starte en aktivitet som endrer atferden til tillitsagenter."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Tilknytt en tillitsagent-tjeneste."</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Gir appen tillatelse til å knyttes til en tillitsagent-tjeneste."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Samhandling med oppdateringer og gjenopprettingssystem"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index e42d714..a655f36c 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Toestaan dat een app controleert op wijzigingen in de trust-status."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Een trust-agent aanleveren."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Hiermee kan een app een trust-agent aanleveren."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Menu met instellingen voor vertrouwensagent starten."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Hiermee kan een app een activiteit starten waarmee het gedrag van de vertrouwensagent wordt gewijzigd."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Binden aan een trust-agentservice"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Toestaan dat een app wordt gebonden aan een trust-agentservice."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interactie met update- en herstelsysteem"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 64609df..c30ad74 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Zezwala aplikacji na monitorowanie zmian w stanie zaufania."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Dostarczaj agenta zaufania."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Zezwala aplikacji na dostarczanie agenta zaufania."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Uruchom menu ustawień zaufanego agenta."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Umożliwia aplikacji uruchamianie czynności, która zmienia działanie zaufanego agenta."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Powiąż z usługą agenta zaufania"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Zezwala aplikacji na powiązanie z usługą agenta zaufania."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakcja z systemem odzyskiwania i aktualizacjami"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 059a85f..2e4e423 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1362,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que uma aplicação registe alterações no trust state."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fornecer um agente fidedigno."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que uma aplicação forneça um agente fidedigno."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular a um serviço de trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que uma aplicação fique vinculada a um serviço de trust agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de recuperação e de atualização"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ec805f5..3df7ecb 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Aplicativos pessoais"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android para trabalho"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que geram gastos"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Faça coisas que podem custar dinheiro."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Suas mensagens"</string>
@@ -401,10 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite que o proprietário utilize interface de nível superior de um plano de fundo. Nunca deve ser necessário para aplicativos normais."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"associar a um interagente de voz"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite que o proprietário use a interface de nível superior de um serviço de interação de voz. Não deve ser necessário para aplicativos comuns."</string>
- <!-- no translation found for permlab_manageVoiceKeyphrases (1252285102392793548) -->
- <skip />
- <!-- no translation found for permdesc_manageVoiceKeyphrases (8476560722907530008) -->
- <skip />
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gerenciar frases-chave de voz"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite ao titular gerenciar as frases-chave para detecção de hotword por voz. Isso nunca será necessário para aplicativos normais."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"usar uma tela remota"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite que o proprietário use a interface de nível superior de uma tela remota. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sujeitar-se a um serviço de widget"</string>
@@ -1365,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que o aplicativo detecte alterações no estado de confiança."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fornecer um agente de confiança."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que um aplicativo forneça um agente de confiança."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associar a um serviço de agente de confiança"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que o aplicativo se associe a um serviço de agente de confiança."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de atualizações e recuperação"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index ba25b52..ff26d8f 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -2190,6 +2190,10 @@
<skip />
<!-- no translation found for permdesc_provide_trust_agent (3865702641053068148) -->
<skip />
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<!-- no translation found for permlab_bind_trust_agent_service (8242093169457695334) -->
<skip />
<!-- no translation found for permdesc_bind_trust_agent_service (7041930026024507515) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 07c32fb..110b243 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -401,10 +401,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei imagini de fundal. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"conectare la un serviciu de interacțiune vocală"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de interacțiune vocală. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
- <!-- no translation found for permlab_manageVoiceKeyphrases (1252285102392793548) -->
- <skip />
- <!-- no translation found for permdesc_manageVoiceKeyphrases (8476560722907530008) -->
- <skip />
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gestionarea expresiilor cheie vocale"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite titularului să gestioneze expresiile cheie pentru detectarea expresiei de activare. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"conectare la un ecran la distanță"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite proprietarului să se conecteze la interfața de nivel superior a unui ecran la distanță. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"conectare la un serviciu widget"</string>
@@ -1365,6 +1363,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite unei aplicații să detecteze modificările în starea de încredere."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Indicați un agent de încredere."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite unei aplicații să indice un agent de încredere."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Asocierea la un serviciu „agenți de încredere”."</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite unei aplicații să se asocieze la un serviciu „agent de încredere”."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interacțiune cu sistemul de recuperare și de actualizare"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a7ca57b..12d1895 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Персональные приложения"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android для бизнеса"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Платные услуги"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Приложение сможет использовать платные услуги."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Сообщения"</string>
@@ -1363,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Приложение сможет отслеживать изменения в статусе доверия."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Доверенный агент"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Предоставление доверенных агентов."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Запуск настроек Trust Agent"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Запуск меню, позволяющего управлять настройками Trust Agent."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Подключение к службе Trust Agents"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Приложение сможет подключаться к службе Trust Agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействовать с системой восстановления и обновлениями"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 5631559..ab596c5 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikácii reagovať na zmeny stavu dôveryhodnosti."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Poskytnúť dôveryhodného agenta"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Umožňuje aplikácii poskytnúť dôveryhodného agenta."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Spustenie ponuky nastavení dôveryhodného agenta"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Umožňuje aplikácii spustiť aktivitu, ktorá zmení správanie dôveryhodného agenta."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Viazanie sa na službu zástupcu dôveryhodnosti"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikácii viazať sa na službu zástupcu dôveryhodnosti."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakcia so systémom aktualizácií a obnovenia"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a51e909..cc06fd3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Osebne aplikacije"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android – službeno"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Plačljive storitve"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Dovolite stvari, za katere bo morda treba plačati."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaša sporočila"</string>
@@ -1363,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Aplikaciji dovoli spremljanje sprememb stanja zaupanja."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Navedba posrednika zaupanja."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Aplikaciji dovoli navesti posrednika zaupanja."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Odpri meni z nastavitvami posrednika zaupanja."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Dovoli aplikaciji zagon dejavnosti, ki spremeni način delovanja posrednika zaupanja."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezovanje s storitvijo posrednikov zaupanja"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Aplikaciji dovoli povezovanje s storitvijo posrednikov zaupanja."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Uporaba sistema za posodobitev in obnovitev"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4b2aa24..099e6ef 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Личне апликације"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android за посао"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Услуге које се плаћају"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Покреће радње које могу да се плаћају."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Поруке"</string>
@@ -1363,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Дозвољава апликацији да прати промене Trust стања."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Обезбеђивање поузданог агента."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Дозвољава апликацији да обезбеди поузданог агента."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Везивање за услугу Trust agents"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозвољава апликацији да се веже за услугу Trust agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Интеракција са системом за ажурирање и опоравак"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f9cd57a..46bb563 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1362,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillåter att en app lyssnar efter ändringar i den betrodda agentens status."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Tillhandahåll en betrodd agent."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Tillåter att en app tillhandahåller en betrodd agent."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind till en tjänst från en betrodd agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillåter att en app binds vid en tjänst från en betrodd agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagera med uppdaterings- och återställningssystemet"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 9573e151..595c807 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1362,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Huruhusu programu kusikiliza mabadiliko katika hali ya kuaminiwa."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Toa wakala wa uaminifu."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Huruhusu programu kutoa wakala wa uaminifu."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Funga kwenye huduma ya dalali wa kuaminiwa"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Huruhusu programu kufungamanisha kwenye huduma ya dalali wa kuaminiwa."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Ingiliana na sasisho na mfumo wa kurejesha"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 68d5442..feabf4f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"อนุญาตให้แอปพลิเคชันฟังการเปลี่ยนแปลงที่มีต่อสถานะความน่าเชื่อถือ"</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"เสนอตัวแทนที่เชื่อถือได้"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"ช่วยให้แอปพลิเคชันสามารถเสนอตัวแทนที่เชื่อถือได้"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"เปิดเมนูการตั้งค่าตัวแทนที่เชื่อถือได้"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"อนุญาตให้แอปพลิเคชันเปิดกิจกรรมที่เปลี่ยนพฤติกรรมตัวแทนที่เชื่อถือได้"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"อนุญาตให้แอปพลิเคชันผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"โต้ตอบกับการอัปเดตและระบบการกู้คืน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 5c926ba..13b629e 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Mga personal na app"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Mga serbisyong ginagastusan mo"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gumawa ng mga bagay na magpapagastos sa iyo."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Iyong mga mensahe"</string>
@@ -1363,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Pinapayagan ang isang application na makinig para sa mga pagbabago sa estado ng trust."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Magbigay ng trust agent."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Pinapayagan ang isang application na magbigay ng trust agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Ilunsad ang menu ng mga setting ng trust agent."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Nagbibigay-daan sa isang application na maglunsad ng aktibidad na nagbabago sa pagkilos ng trust agent."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Sumailalim sa isang serbisyo ng trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Pinapayagan ang isang application na sumailalim sa isang serbisyo ng trust agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Makipag-ugnay sa system ng pag-update at pagbawi"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 3583fb0..0c19b03 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Kişisel uygulamalar"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Size maliyet getiren hizmetler"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Size maliyet getirebilecek işlemler yapma."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajlarınız"</string>
@@ -1363,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Bir uygulamanın, güven durumundaki değişiklikleri dinlemesine izin verir."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Güven aracısı sağlama."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Bir uygulamanın güven aracısı sağlamasına izin verir."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Güven aracı hizmetine bağlan"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Bir uygulamanın, güven aracı hizmetine bağlanmasına izin verir."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Güncelleme ve kurtarma sistemiyle etkileşim kur"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index fdb40b5..0d56975b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -189,7 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Особисті додатки"</string>
- <string name="managed_profile_label" msgid="4287077106125758391">"Android для роботи"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android для бізнесу"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Служби, які потребують оплати"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Виконувати дії, які потребують оплати."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ваші повідомл."</string>
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Дозволяє додатку відстежувати зміни в стані довіри."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Призначення довірчого агента."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Додаток може призначати довірчого агента."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Запустити меню налаштувань довірчого агента"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Додаток може запускати функцію, яка змінює поведінку довірчого агента."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Прив’язуватися до служби довірчих агентів"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозволяє додатку прив’язуватися до служби довірчих агентів."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Взаємодіяти з оновленнями системи та системою відновлення."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 022efcc..dd13b45 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
<string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
<string name="user_owner_label" msgid="6465364741001216388">"Ứng dụng cá nhân"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Dịch vụ tính tiền của bạn"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Thực hiện những tác vụ mà bạn có thể phải trả tiền."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Tin nhắn của bạn"</string>
@@ -1363,6 +1362,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Cho phép ứng dụng quan sát các thay đổi ở trạng thái đáng tin cậy."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Cung cấp tác nhân đáng tin cậy."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Cho phép ứng dụng cung cấp tác nhân đáng tin cậy."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Liên kết với một dịch vụ của đại lý đáng tin cậy"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Cho phép ứng dụng liên kết với một dịch vụ của đại lý đáng tin cậy."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Tương tác với hệ thống khôi phục và bản cập nhật"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f2090a2..3a07366 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -401,10 +401,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允许用户绑定到壁纸的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"绑定到语音互动器"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允许应用绑定到语音互动服务的顶级接口。普通应用绝不需要此权限。"</string>
- <!-- no translation found for permlab_manageVoiceKeyphrases (1252285102392793548) -->
- <skip />
- <!-- no translation found for permdesc_manageVoiceKeyphrases (8476560722907530008) -->
- <skip />
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"管理语音关键短语"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"允许应用管理用于语音启动指令检测的关键短语。普通应用绝不需要此权限。"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"绑定至远程显示屏"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允许应用绑定至远程显示屏的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到小部件服务"</string>
@@ -1365,6 +1363,10 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"允许应用检测信任状态的变化。"</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"提供信任的代理。"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"允许应用提供信任的代理。"</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"绑定至信任的代理服务"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允许应用绑定至信任的代理服务。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"与更新和恢复系统互动"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 3ebf416..8e290b5 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
<string name="user_owner_label" msgid="6465364741001216388">"個人應用程式"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android 企業版"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"付費服務"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"執行需付費的操作或服務。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"您的訊息"</string>
@@ -1363,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"允許應用程式聽取信任狀態的變更。"</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"提供信任的代理程式。"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"允許應用程式提供信任的代理程式。"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"啟動信任的代理程式設定選單。"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"允許應用程式啟動可變更信任的代理程式行為的活動。"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"與更新和復原系統互動"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 85e47ac..6ab2b48 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -189,8 +189,7 @@
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
<string name="user_owner_label" msgid="6465364741001216388">"個人應用程式"</string>
- <!-- no translation found for managed_profile_label (4287077106125758391) -->
- <skip />
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android 企業版"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"需要額外費用的服務。"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"執行需付費的作業或服務。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"您的簡訊"</string>
@@ -1363,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"允許應用程式接聽信任狀態變更。"</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"提供信任的代理程式。"</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"允許應用程式提供信任的代理程式。"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"啟動信任的代理程式設定選單。"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"允許應用程式啟動可變更信任的代理程式行為的活動。"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"與更新和還原系統互動"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 639d400..07238c3 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1362,6 +1362,8 @@
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Ivumela uhlelo lokusebenza ukuthi lilalelele izinguquko kusimo sethemba."</string>
<string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Nikeza umsebenzeli owethembekile."</string>
<string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ivumela uhlelo lokusebenza ukunikeza umsebenzeli owethembekile."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Qalisa imenyu yezilungiselelo zomsebenzeli wethemba."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Ivumela uhlelo lokusebenza ukuthi luqalise umsebenzi oguqula ukuziphatha komsebenzeli wethemba."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bophezela kusevisi yomenzeli wethemba"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ivumela uhlelo lokusebenza ukuthi libophezeleke kusevisi yomenzeli wethemba."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Ixhumana nesibuyekezo nesistimu yokutakula"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e807d69..8d8f69e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2432,6 +2432,30 @@
<!-- Sets the state-based animator for the View. -->
<attr name="stateListAnimator" format="reference"/>
+
+ <!-- Tint to apply to the background. -->
+ <attr name="backgroundTint" format="color" />
+
+ <!-- Blending mode used to apply the background tint. -->
+ <attr name="backgroundTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3021,7 +3045,29 @@
<!-- Indicates the initial checked state of this button. -->
<attr name="checked" format="boolean" />
<!-- Drawable used for the button graphic (e.g. checkbox, radio button, etc). -->
- <attr name="button" format="reference"/>
+ <attr name="button" format="reference" />
+ <!-- Tint to apply to the button graphic. -->
+ <attr name="buttonTint" format="color" />
+ <!-- Blending mode used to apply the button graphic tint. -->
+ <attr name="buttonTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
</declare-styleable>
<declare-styleable name="CheckedTextView">
<!-- Indicates the initial checked state of this text. -->
@@ -3106,6 +3152,28 @@
<!-- Determines whether to measure all children or just those in
the VISIBLE or INVISIBLE state when measuring. Defaults to false. -->
<attr name="measureAllChildren" format="boolean" />
+ <!-- Tint to apply to the foreground. -->
+ <attr name="foregroundTint" format="color" />
+ <!-- Blending mode used to apply the foreground tint. -->
+ <attr name="foregroundTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
</declare-styleable>
<declare-styleable name="ExpandableListView">
<!-- Indicator shown beside the group View. This can be a stateful Drawable. -->
@@ -3211,6 +3279,10 @@
<!-- @hide The alpha value (0-255) set on the ImageView's drawable. Equivalent
to calling ImageView.setAlpha(int), not the same as View.setAlpha(float). -->
<attr name="drawableAlpha" format="integer" />
+ <!-- Tint to apply to the image. -->
+ <attr name="tint" />
+ <!-- Blending mode used to apply the image tint. -->
+ <attr name="tintMode" />
</declare-styleable>
<declare-styleable name="ToggleButton">
<!-- The text for the button when it is checked. -->
@@ -3401,6 +3473,98 @@
<!-- Defines if the associated drawables need to be mirrored when in RTL mode.
Default is false -->
<attr name="mirrorForRtl" format="boolean" />
+ <!-- Tint to apply to the progress indicator. -->
+ <attr name="progressTint" format="color" />
+ <!-- Blending mode used to apply the progress indicator tint. -->
+ <attr name="progressTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+ <!-- Tint to apply to the progress indicator background. -->
+ <attr name="progressBackgroundTint" format="color" />
+ <!-- Blending mode used to apply the progress indicator background tint. -->
+ <attr name="progressBackgroundTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+ <!-- Tint to apply to the secondary progress indicator. -->
+ <attr name="secondaryProgressTint" format="color" />
+ <!-- Blending mode used to apply the secondary progress indicator tint. -->
+ <attr name="secondaryProgressTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+ <!-- Tint to apply to the indepterminate progress indicator. -->
+ <attr name="indeterminateTint" format="color" />
+ <!-- Blending mode used to apply the indeterminate progress indicator tint. -->
+ <attr name="indeterminateTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+ <!-- Tint to apply to the background. -->
+ <attr name="backgroundTint" />
+ <!-- Blending mode used to apply the background tint. -->
+ <attr name="backgroundTintMode" />
</declare-styleable>
<declare-styleable name="SeekBar">
@@ -3410,6 +3574,28 @@
<attr name="thumbOffset" format="dimension" />
<!-- Whether to split the track and leave a gap for the thumb drawable. -->
<attr name="splitTrack" format="boolean" />
+ <!-- Tint to apply to the button graphic. -->
+ <attr name="thumbTint" format="color" />
+ <!-- Blending mode used to apply the button graphic tint. -->
+ <attr name="thumbTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
</declare-styleable>
<declare-styleable name="StackView">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 814d8fc0..a8735cb 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -873,17 +873,33 @@
<!-- The name of the logical parent of the activity as it appears in the manifest. -->
<attr name="parentActivityName" format="string" />
- <!-- Define an activity that will persist across reboots. If such an activity is in the
- Recents list when the device is shut off it will appear in the Recents list when
- the device is next powered on. To be persisted all activities in the task from the
- root activity up to the last activity before a <em>break</em> must be declared with
- the persistable attribute. A <em>break</em> is the first activity after the root
- started with Intent.FLAG_CLEAR_TASK_WHEN_RESET.
+ <!-- Define how an activity persist across reboots. Activities defined as "never" will not
+ be persisted. Those defined as "always" will be persisted. Those defined as "taskOnly"
+ will persist the root activity of the task only. See below for more detail as to
+ what gets persisted. -->
+ <attr name="persistableMode">
+ <!-- The default. If this activity forms the root of a task then that task will be
+ persisted across reboots but only the launching intent will be used. All
+ activities above this activity in the task will not be persisted. In addition
+ this activity will not be passed a PersistableBundle into which it could have
+ stored its state. -->
+ <enum name="persistRootOnly" value="0" />
+ <!-- If this activity forms the root of a task then that task will not be persisted
+ across reboots -->
+ <enum name="doNotPersist" value="1" />
+ <!-- If this activity forms the root of a task then the task and this activity will
+ be persisted across reboots. If the activity above this activity is also
+ tagged with the attribute <code>"persist"</code> then it will be persisted as well.
+ And so on up the task stack until either an activity without the
+ <code>persistableMode="persistAcrossReboots"</code> attribute or one that was launched
+ with the flag Intent.FLAG_CLEAR_TASK_WHEN_RESET is encountered.
- <p>Activities that are declared with the persistable attribute will be provided with a
- forced-persistable Bundle in onCreate() and onSavedInstanceState(), and must only
- be passed a persistable Bundle in their Intent.extras. -->
- <attr name="persistable" format="boolean" />
+ <p>Activities that are declared with the persistAcrossReboots attribute will be
+ provided with a PersistableBundle in onSavedInstanceState(), These activities may
+ use this PeristableBundle to save their state. Then, following a reboot, that
+ PersistableBundle will be provided back to the activity in its onCreate() method. -->
+ <enum name="persistAcrossReboots" value="2" />
+ </attr>
<!-- This attribute specifies that an activity shall become the root activity of a
new task each time it is launched. Using this attribute permits the user to
@@ -1623,7 +1639,7 @@
<!-- @hide This broacast receiver will only receive broadcasts for the
primary user. Can only be used with receivers. -->
<attr name="primaryUserOnly" format="boolean" />
- <attr name="persistable" />
+ <attr name="persistableMode" />
<attr name="allowEmbedded" />
<attr name="documentLaunchMode" />
<attr name="maxRecents" />
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 9f6c7ad..f304514 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -143,7 +143,7 @@
<color name="keyguard_avatar_nick_color">#ffffffff</color>
<color name="keyguard_avatar_frame_pressed_color">#ff35b5e5</color>
- <color name="accessibility_focus_highlight">#80ffff00</color>
+ <color name="accessibility_focus_highlight">#bf39b500</color>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 202c127..c5ce229 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2136,7 +2136,7 @@
<public type="attr" name="colorControlActivated" />
<public type="attr" name="colorButtonNormal" />
<public type="attr" name="colorControlHighlight" />
- <public type="attr" name="persistable" />
+ <public type="attr" name="persistableMode" />
<public type="attr" name="titleTextAppearance" />
<public type="attr" name="subtitleTextAppearance" />
<public type="attr" name="slideEdge" />
@@ -2190,6 +2190,22 @@
<public type="attr" name="searchKeyphraseSupportedLocales" />
<public type="attr" name="windowTransitionBackgroundFadeDuration" />
<public type="attr" name="overlapAnchor" />
+ <public type="attr" name="progressTint" />
+ <public type="attr" name="progressTintMode" />
+ <public type="attr" name="progressBackgroundTint" />
+ <public type="attr" name="progressBackgroundTintMode" />
+ <public type="attr" name="secondaryProgressTint" />
+ <public type="attr" name="secondaryProgressTintMode" />
+ <public type="attr" name="indeterminateTint" />
+ <public type="attr" name="indeterminateTintMode" />
+ <public type="attr" name="backgroundTint" />
+ <public type="attr" name="backgroundTintMode" />
+ <public type="attr" name="foregroundTint" />
+ <public type="attr" name="foregroundTintMode" />
+ <public type="attr" name="buttonTint" />
+ <public type="attr" name="buttonTintMode" />
+ <public type="attr" name="thumbTint" />
+ <public type="attr" name="thumbTintMode" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6e1b5ef..e31dbaf 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2971,6 +2971,13 @@
to your voicemail inbox.</string>
<!-- Title of an application permission, listed so the user can choose whether
+ they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permlab_readAllVoicemail">read all voicemail</string>
+ <!-- Description of an application permission, listed so the user can choose whether
+ they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_readAllVoicemail">Allows the app to read all your voicemails.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
<string name="permlab_writeGeolocationPermissions">modify Browser geolocation permissions</string>
<!-- Description of an application permission, listed so the user can choose whether
diff --git a/docs/html/google/play-services/games.jd b/docs/html/google/play-services/games.jd
index 94f6715..a73f688 100644
--- a/docs/html/google/play-services/games.jd
+++ b/docs/html/google/play-services/games.jd
@@ -1,4 +1,5 @@
page.title=Google Play Game Services
+page.tags="games"
header.hide=1
@jd:body
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index 049e6fe..4332953 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -8,7 +8,6 @@
<h2>In this document</h2>
<ol>
- <li><a href="#Install">Install the Google Play Services SDK</a></li>
<li><a href="#Setup">Add Google Play Services to Your Project</a></li>
<li><a href="#Proguard">Create a Proguard Exception</a></li>
<li><a href="#ensure">Ensure Devices Have the Google Play services APK</a></li>
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index 40618a3..2fa029f 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -15,7 +15,9 @@
<ol id="toc44" class="hide-nested">
<li><a href="#Behaviors">Important Behavior Changes</a>
<ol>
+ <li><a href="#ART">New Android Runtime (ART)</a></li>
<li><a href="#BehaviorNotifications">If your app implements notifications...</a></li>
+ <li><a href="#BehaviorMediaControl">If your app uses RemoteControlClient...</a></li>
<li><a href="#BehaviorFullscreen">If your app uses fullScreenIntent...</a></li>
<li><a href="#BehaviorGetRecentTasks">If your app uses ActivityManager.getRecentTasks()...</a></li>
</ol>
@@ -23,9 +25,10 @@
<li><a href="#UI">User Interface</a>
<ol>
<li><a href="#MaterialDesign">Material design support</a></li>
+ <li><a href="#DoNotDisturb">Do Not Disturb mode</a></li>
<li><a href="#LockscreenNotifications">Lockscreen notifications</a></li>
<li><a href="#NotificationsMetadata">Notifications metadata</a></li>
- <li><a href="#Recents">Concurrent documents and activities in Recents screen</a></li>
+ <li><a href="#Recents">Concurrent documents and activities in the Recents screen</a></li>
<li><a href="#WebView">WebView updates</a></li>
</ol>
</li>
@@ -41,7 +44,7 @@
</li>
<li><a href="#Multimedia">Multimedia</a>
<ol>
- <li><a href="#Camera-v2">Camera V2</a></li>
+ <li><a href="#Camera-v2">Camera v2 API</a></li>
<li><a href="#AudioPlayback">Audio playback</a></li>
<li><a href="#MediaPlaybackControl">Media playback control</a></li>
</ol>
@@ -55,7 +58,7 @@
<ol>
<li><a href="#Multinetwork">Dynamic network selection and seamless handoff</a></li>
<li><a href="#BluetoothBroadcasting">Bluetooth broadcasting</a></li>
- <li><a href="#NFCEnhancements">NFC enhancements for payments</a></li>
+ <li><a href="#NFCEnhancements">NFC enhancements</a></li>
</ol>
</li>
<li><a href="#Power">Power Efficiency</a>
@@ -71,7 +74,7 @@
</li>
<li><a href="#Printing">Printing Framework</a>
<ol>
- <li><a href="#PDFRender">PDF rendering</a></li>
+ <li><a href="#PDFRender">Render PDF as bitmap</a></li>
</ol>
</li>
<li><a href="#TestingA11y">Testing & Accessibility</a>
@@ -96,73 +99,130 @@
</div>
</div>
-<p>L is an upcoming release for the Android platform
-that offers new features for users and app developers. This document provides
-an introduction to the most notable new APIs.</p>
+<p>The L Developer Preview gives you an advance look at the upcoming release for
+the Android platform,
+which offers new features for users and app developers. This document provides
+an introduction to the most notable APIs.</p>
-<p>L is currently available as a <strong>developer preview</strong> intended
-for early adopters and testers. If you are interested in influencing the
-direction of the Android framework,
-<a href="{@docRoot}preview/setup-sdk.html">give the L Developer Preview a
-try</a> and send us your feedback!</p>
+<p>The L Developer Preview is intended for <strong>developer early adopters</strong> and
+<strong>testers</strong>. If you are interested in influencing the direction of the
+Android framework, <a href="{@docRoot}preview/setup-sdk.html">give the L
+Developer Preview a try</a> and send us your feedback!</p>
-<p class="caution"><strong>Caution:</strong>You should not publish apps
-using L Developer Preview to the Google Play store.</p>
+<p class="caution"><strong>Caution:</strong> Do not not publish apps
+that use the L Developer Preview to the Google Play store.</p>
+
+<p class="note"><strong>Note:</strong> This document often refers to classes and
+methods that do not yet have reference material available on <a
+href="{@docRoot}">developer.android.com</a>. These API elements are
+formatted in {@code code style} in this document (without hyperlinks). For the
+preliminary API documentation for these elements, download the <a
+href="{@docRoot}preview/l-developer-preview-reference.zip">preview
+reference</a>.</p>
<h2 id="Behaviors">Important Behavior Changes</h2>
<p>If you have previously published an app for Android, be aware that your app
- might be affected by changes in L.</p>
+ might be affected by changes in the upcoming release.</p>
+
+<h3 id="ART">New Android Runtime (ART)</h3>
+
+<p>The 4.4 release introduced a new, experimental Android runtime, ART. Under
+4.4, ART was optional, and the default runtime remained Dalvik. With the L Developer Preview, ART is
+now the default runtime.</p>
+
+<p>For an overview of ART's new features, see
+<a href="https://source.android.com/devices/tech/dalvik/art.html">Introducing
+ART</a>. Some of the major new features are:</p>
+
+<ul>
+ <li>Ahead-of-Time (AOT) compilation</li>
+ <li>Improved garbage collection (GC)</li>
+ <li>Improved debugging support</li>
+</ul>
+
+<p>Most Android apps should just work without change under ART. However, some
+techniques that work on Dalvik do not work on ART. For information about the
+most important issues, see
+<a href="{@docRoot}guide/practices/verifying-apps-art.html">Verifying App
+Behavior on the Android Runtime (ART)</a>. Pay particular attention if:</p>
+
+<ul>
+ <li>Your app uses Java Native Interface (JNI) to run C/C++ code.</li>
+ <li>You use development tools that generate non-standard code (such as some
+ obfuscators).</li>
+ <li>You use techniques that are incompatible with compacting garbage
+ collection. (ART does not currently implement compacting GC, but
+ compacting GC is under development in the Android Open-Source
+ Project.)</li>
+</ul>
<h3 id="BehaviorNotifications">If your app implements notifications...</h3>
-<p>Notifications will be drawn with dark text atop white (or very light)
+<p>Notifications are drawn with dark text atop white (or very light)
backgrounds to match the new material design widgets. Make sure that all your
-notifications look right with the new color scheme. You should remove or update
-assets and text styles that involve color. The system will automatically invert
-action icons in notifications. Use
-{@code android.app.Notification.Builder.setColor()} to set an accent color
-in a circle behind your {@code Notification.icon} image.</p>
+notifications look right with the new color scheme:</p>
-<p>The system will ignore all non-alpha channels in action icons and the main
-notification icon, so you should assume that these icons will be alpha-only.
-</p>
+<ul>
+
+ <li>Update or remove assets that involve color.</li>
+
+ <li>The system automatically inverts action icons in notifications. Use
+ {@code android.app.Notification.Builder.setColor()} to set an accent color
+ in a circle behind your {@link android.app.Notification#icon} image.</li>
+
+ <li>The system ignores all non-alpha channels in action icons and the main
+ notification icon. You should assume that these icons are alpha-only.</li>
+
+</ul>
<p>If you are currently adding sounds and vibrations to your notifications by
using the {@link android.media.Ringtone}, {@link android.media.MediaPlayer},
-or {@link android.os.Vibrator} classes, make sure to remove this code so that
-the system can present notifications correctly in Do not disturb mode. You
-should use the {@link android.app.Notification.Builder} methods instead to add
-sounds and vibration.
-</p>
+or {@link android.os.Vibrator} classes, remove this code so that
+the system can present notifications correctly in <a href="#DoNotDisturb">Do Not Disturb</a> mode.
+Instead, use the {@link android.app.Notification.Builder} methods instead to add
+sounds and vibration.</p>
<h3 id="BehaviorMediaControl">If your app uses RemoteControlClient...</h3>
-<p>Lockscreens in L will not show transport controls for your
+<p>Lockscreens in the L Developer Preview do not show transport controls for your
{@link android.media.RemoteControlClient}. Instead, your app can provide
media playback control from the lockscreen through a media notification. This
gives your app more control over the presentation of media buttons, while
providing a consistent experience for users across the lockscreen and
unlocked device.</p>
-<p>You must call {@code Notification.Builder.setVisibility(Notification.VISIBILITY_PUBLIC)} to mark your media notification as safe to reveal, even when the lockscreen is secured
-with a PIN, pattern, or password.</p>
+<p>Call {@code
+Notification.Builder.setVisibility(Notification.VISIBILITY_PUBLIC)} to mark a
+notification as safe to display on the lockscreen (even when the lockscreen is
+secured with a PIN, pattern, or password). For more information, see
+<a href="#LockscreenNotifications">Lockscreen Notifications</a>.</p>
<h3 id="BehaviorFullscreen">If your app uses fullScreenIntent...</h3>
<p>Notifications now appear in a small floating window if all these conditions
-are met: the user’s activity is in fullscreen mode, the screen is on, and the
-device is unlocked. If your app implements fullscreen activities, make sure that
+are met:</p>
+
+<ul>
+ <li>The user’s activity is in fullscreen mode,</li>
+ <li>The screen is on, and</li>
+ <li>The device is unlocked</li>
+</ul>
+
+<p>If your app implements fullscreen activities, make sure that
these heads-up notifications are presented correctly.</p>
<h3 id="BehaviorGetRecentTasks">If your app uses ActivityManager.getRecentTasks()...</h3>
-<p>With the introduction of the new document tasks feature in L (see below),
-the {@code android.app.ActivityManager.getRecentTasks()} method is now
-deprecated to improve user privacy. For backwards
-compatibility, it will still return a small subset of its data including the
+<p>With the introduction of the new <em>concurrent documents and activities tasks</em> feature in the upcoming
+release (see <a href="#Recents">Concurrent documents and activities in Recents
+screen</a> below),
+the {@link android.app.ActivityManager#getRecentTasks
+ActivityManager.getRecentTasks()} method is now
+deprecated to improve user privacy. For backward
+compatibility, this method still returns a small subset of its data, including the
calling application’s own tasks and possibly some other non-sensitive tasks
-such as home. If your app is using this method to retrieve its own tasks,
+(such as Home). If your app is using this method to retrieve its own tasks,
use {@code android.app.ActivityManager.getAppTasks()} instead to retrieve that
information.</p>
@@ -170,11 +230,15 @@
<h3 id="MaterialDesign">Material design support</h3>
-<p>The L Developer Preview adds support for the material design style. You can create
-material design apps that are visually dynamic and have UI element transitions
-which feel natural and delightful to users. This support includes:</p>
+
+<p>The upcoming release adds support for Android's new <em>material</em> design
+style. You can create
+apps with material design that are visually dynamic and have UI element transitions
+that feel natural to users. This support includes:</p>
+
<ul>
- <li>The Material theme</li>
+
+ <li>The material theme</li>
<li>View shadows</li>
<li>The {@code RecyclerView} widget</li>
<li>Drawable animation and styling effects</li>
@@ -182,8 +246,9 @@
<li>Animators for view properties based on the state of a view</li>
<li>Customizable UI widgets and app bars with color palettes that you control</li>
</ul>
+
<p>To learn more about adding material design functionality to your app, see
-<a href="{@docRoot}preview/material/index.html">Material design on Android</a>.</p>
+<a href="{@docRoot}preview/material/index.html">Material Design</a>.</p>
<h3 id="LockscreenNotifications">Lockscreen notifications</h3>
<p>Lockscreens in the L Developer Preview have the ability to present notifications.
@@ -194,29 +259,57 @@
displayed over the secure lockscreen. To control the visibility level, call
{@code android.app.Notification.Builder.setVisibility()} and specify one of these
values:</p>
+
<ul>
<li>{@code VISIBILITY_PRIVATE}. Shows basic information, such as the
notification’s icon, but hides the notification’s full content. If you want to
provide a redacted public version of your notification for the system to display
-on a secure lockscreen, set the public notification object in the <code>publicVersion</code>
-field.</li>
+on a secure lockscreen, create a public notification object and put a reference
+to it in the private notification's {@code publicVersion} field.</li>
<li>{@code VISIBILITY_PUBLIC}. Shows the notification’s full content. This is
the system default if visibility is left unspecified.</li>
<li>{@code VISIBILITY_SECRET}. Shows only the most minimal information,
excluding even the notification’s icon.</li>
</ul>
-<h3 id="NotificationsMetadata">Notifications metadata</h3>
-<p>The L Developer Preview uses metadata associated with your app notifications
-to more intelligently sort your notifications. The metadata you set also
-controls how the system presents your app notifications when the user is in <em>Do
-not disturb</em> mode. When constructing your notification, you can call the
-following methods in {@code android.app.Notification.Builder}:</p>
+<h3 id="DoNotDisturb">Do Not Disturb mode</h3>
+
+<p>The L Developer Preview introduces a new <em>Do Not Disturb</em> mode. When
+the user puts the device in <em>Do Not Disturb</em> mode, the device limits
+the frequency of the notifications it shows the user (when the user
+wants to avoid distractions). The user can
+customize the feature in a number of ways, such as:</p>
<ul>
-<li>{@code setCategory()}. Allows the system to handle your app notifications
-in <em>Do not disturb mode</em> (for example, if your notification represents an
-incoming call, instant message, or alarm).</li>
+ <li>Specifying important people, whose calls should go through even when
+ the device is in <em>Do Not Disturb</em> mode.</li>
+ <li>Setting custom categories to allow notifications when the device is in
+ <em>Do Not Disturb</em> mode. Examples of such categories include phone
+ calls and direct communications (like Hangouts and Skype calls).</li>
+ <li>Setting rules so <em>Do Not Disturb</em> automatically goes into effect in
+ certain conditions (like at particular times of day).</li>
+</ul>
+
+<p>You should add the appropriate metadata to your app notifications to help
+make sure <em>Do Not Disturb</em> mode handles them properly. For example, if
+your app is an alarm clock,
+you can tag the notification as an alarm so it will wake the user up even if the
+device is in <em>Do Not Disturb</em> mode. For more information, see <a
+href="NotificationsMetadata">Notifications metadata</a>.</p>
+
+<h3 id="NotificationsMetadata">Notifications metadata</h3>
+<p>The L Developer Preview uses metadata associated with your app notifications
+to sort the notifications more intelligently. The metadata you set also
+controls how the system presents your app notifications when the user is in <em>Do
+Not Disturb</em> mode. To set the metadata, call the following methods in
+{@code android.app.Notification.Builder} when you construct the
+notification:</p>
+
+<ul>
+<li>{@code setCategory()}. Depending on the message category, this tells
+the system how to handle your app notifications when the device is
+in <em>Do Not Disturb</em> mode (for example, if your notification represents an
+incoming call, instant message, or alarm).
<li>{@code setPriority()}. Notifications with the priority field set to
{@code PRIORITY_MAX} or {@code PRIORITY_HIGH} will appear in a small floating
window if the notification also has sound or vibration.</li>
@@ -231,30 +324,35 @@
<p>In previous releases, the
<a href="{@docRoot}design/get-started/ui-overview.html">Recents screen</a>
could only display a single task for each app that the user interacted with
-most recently. The L Developer Preview allows your app to open additional tasks
-for concurrent activities or documents. This feature facilitates multitasking
+most recently. The L Developer Preview enables your app to open more tasks as
+needed for additional concurrent activities for documents.
+This feature facilitates multitasking
by letting users quickly switch between individual activities and documents
-from the Recents screen. Examples of such concurrent tasks might include web
-pages in a browser app, documents in a productivity app, concurrent matches in
+from the Recents screen, with a consistent switching experience across all apps.
+Examples of such concurrent tasks might include open tabs in a web
+browser app, documents in a productivity app, concurrent matches in
a game, or chats in a messaging app. Your app can manage its tasks
through the {@code android.app.ActivityManager.AppTask} class.</p>
<p>To insert a logical break so that the system treats your activity as a new
-document, use {@code android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT} when
+task, use {@code android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT} when
launching the activity with {@link android.app.Activity#startActivity(android.content.Intent) startActivity()}. You can also get this behavior by declaring the
<a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a>
attribute {@code documentLaunchMode="intoExisting"} or {@code ="always"} in your
manifest.</p>
<p>You can also mark that a task should be removed from the Recents screen
-when all its activities are closed by using {@code android.content.Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} when starting the root activity for
+when all its activities are closed. To do this, use {@code
+android.content.Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} when starting the
+root activity for
the task. You can also set this behavior for an activity by declaring the
<a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a>
attribute {@code autoRemoveFromRecents=“true”} in your manifest.</p>
<p>To avoid cluttering the Recents screen, you can set the maximum number of
-tasks from your app that can appear in the Recents screen through the
-<a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a> attribute {@code android:maxRecent}. The current maximum that can be specified
+tasks from your app that can appear in that screen. To do this, set the
+<a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a>
+attribute {@code android:maxRecent}. The current maximum that can be specified
is 100 tasks per user.</a></p>
<h3 id="WebView">WebView updates</h3>
@@ -274,16 +372,20 @@
<h3 id="IME">IME bug fixes and improvements</h3>
<p>Beginning in the L Developer Preview, users can more easily switch between
-all input method editors (IME) <a href="{@docRoot}guide/topics/text/creating-input-method.html">supported by the platform</a>. Performing the designated
+all <a href="{@docRoot}guide/topics/text/creating-input-method.html">input
+method editors (IME)</a> supported by the platform. Performing the designated
switching action (usually touching a Globe icon on the soft keyboard) will cycle
among all such IMEs. This change takes place in
-{@code android.view.inputmethod.InputMethodManager.shouldOfferSwitchingToNextInputMethod()}.</p>
+{@link android.view.inputmethod.InputMethodManager#shouldOfferSwitchingToNextInputMethod
+InputMethodManager.shouldOfferSwitchingToNextInputMethod()}.</p>
-<p>In addition, the framework will now check whether the next IME includes a
-switching mechanism at all, thus supporting switching to the IME after it. An
+<p>In addition, the framework now checks whether the next IME includes a
+switching mechanism at all (and, thus, whether that IME supports switching to
+the IME after it). An
IME with a switching mechanism will not cycle to an IME without one. This
change takes place in
-{@code android.view.inputmethod.InputMethodManager.switchToNextInputMethod()}.
+{@link android.view.inputmethod.InputMethodManager#switchToNextInputMethod
+InputMethodManager.switchToNextInputMethod}.
<p>To see an example of how to use the updated IME-switching APIs, refer to the
updated soft-keyboard implementation sample in this release.</p>
@@ -314,17 +416,20 @@
</manifest>
</pre>
-<p>For more information about using OpenGL ES, including how to check the device’s supported OpenGL ES version at runtime, see the <a href="{@docRoot}/guide/topics/graphics/opengl.html">OpenGL ES API guide</a>.</p>
+<p>For more information about using OpenGL ES, including how to check the device’s supported OpenGL ES version at runtime, see the <a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL ES API guide</a>.</p>
<h2 id="Multimedia">Multimedia</h2>
-<h3 id="Camera=v2">Camera v2 API</h3>
+<h3 id="Camera-v2">Camera v2 API</h3>
<p>The L Developer Preview introduces the new {@code android.hardware.camera2}
-API to facilitate fine grain photo capture and image processing. You can now programmatically access the camera devices available to the system with {@code CameraManager.getCameraIdList()} and connect to a specific device with {@code CameraManager.openCamera()}. To start capturing images, you
-need to create a {@code CameraCaptureSession} and specify the
-{@link android.view.Surface} objects to send the captured images. The {@code CameraCaptureSession} can be configured to take single shots or multiple images
-in a burst.</p>
+API to facilitate fine-grain photo capture and image processing. You can now
+programmatically access the camera devices available to the system with {@code
+CameraManager.getCameraIdList()} and connect to a specific device with {@code
+CameraManager.openCamera()}. To start capturing images, create a {@code
+CameraCaptureSession} and specify the {@link android.view.Surface} objects for
+the captured images. The {@code CameraCaptureSession} can be configured to take
+single shots or multiple images in a burst.</p>
<p>To be notified when new images are captured, implement the
{@code CameraCaptureSession.CaptureListener()} interface and set it in your
@@ -334,16 +439,17 @@
{@code CaptureResult}.</p>
<h3 id="AudioPlayback">Audio playback</h3>
-<p>This release includes the following changes for
- {@code android.media.AudioTrack}:</p>
+<p>This release includes the following changes to
+ {@link android.media.AudioTrack}:</p>
<ul>
<li>Your app can now supply audio data in floating-point format
({@code android.media.AudioFormat.ENCODING_PCM_FLOAT}). This permits greater
dynamic range, more consistent precision, and greater headroom. Floating-point arithmetic is especially useful during intermediate calculations. Playback
-end-points use integer format for audio data, and with lower bit-depth. In L
-Developer Preview, portions of the internal pipeline are not yet floating-point.
- <li>Your app can now supply audio data as a {@code ByteBuffer}, in the same
-format as provided by {@code MediaCodec}.
+end-points use integer format for audio data, and with lower bit-depth. (In the
+L Developer Preview, portions of the internal pipeline are not yet
+floating-point.)
+ <li>Your app can now supply audio data as a {@link java.nio.ByteBuffer}, in the same
+format as provided by {@link android.media.MediaCodec}.
<li>The {@code WRITE_NON_BLOCKING} option can simplify buffering and
multithreading for some apps.
</ul>
@@ -352,8 +458,8 @@
<p>You can now build your own media controller app with the new
{@code android.media.session.MediaController} class, which provides
simplified transport controls APIs that replace those in
-{@code android.media.RemoteControlClient}. The {@code MediaController} class
-allows thread-safe control of playback from a non UI process, making it easier
+{@link android.media.RemoteControlClient}. The {@code MediaController} class
+allows thread-safe control of playback from a non-UI process, making it easier
to control your media playback service from your app’s user interface.
<p>You can also create multiple controllers to send playback commands,
@@ -362,14 +468,16 @@
call {@code MediaSession.getSessionToken()} to request an access
token in order for your app to interact with the session.</p>
-<p>Send transport commands such as "play", "stop", "skip", and
+<p>You can now send transport commands such as "play", "stop", "skip", and
"set rating" by using {@code MediaController.TransportControls}. To handle
-in-bound media transport commands from controllers attached to the session, you
-should override the callback methods in
+in-bound media transport commands from controllers attached to the session,
+override the callback methods in
{@code MediaSession.TransportControlsCallback}.</p>
<p>You can also create rich notifications that allow playback control tied to a
-media session with the new {@code android.app.Notification.MediaStyle} class.</p>
+media session with the new {@code android.app.Notification.MediaStyle} class. By
+using the new notification and media APIs, you will ensure that the System UI
+knows about your playback and can extract and show album art.</p>
<h2 id="Storage">Storage</h2>
@@ -381,46 +489,58 @@
has access to all its child directories and content.</p>
<p>To get the absolute paths to directories on external storage devices where
-applications can store media files, call the
-{@code android.content.Context.getExternalMediaDirs()} method. No additional
+applications can store media files, call the new
+{@code android.content.Context.getExternalMediaDirs()} method. No
+additional
permissions are needed by your app to read or write to the returned paths.
-External storage devices here are those considered by the system to be a
+In this context, "external storage devices" are those devices which the system
+considers to be a
permanent part of the device, and includes emulated external storage and
physical media slots such as SD cards in battery compartments.</p>
<p>If you want to access a document in an existing directory, call the
-{@code android.provider.DocumentsContract.buildDocumentViaUri()} method and pass
-in a Uri representing the path to the parent directory and the target document
-ID. The method returns a new {@link android.net.Uri} with which your app can
+{@code android.provider.DocumentsContract.buildDocumentViaUri()} method.
+Pass the method a URI representing the path to the parent directory, and the
+target document
+ID. The method returns a new {@link android.net.Uri} which your app can
use to write media content with {@code DocumentsContract.createDocument()}.
<h2 id="Wireless">Wireless & Connectivity</h2>
<h3 id="Multinetwork">Dynamic network selection and seamless handoff</h3>
-<p>The L Developer Preview provides new multi-networking APIs for your app to
+<p>The L Developer Preview provides new multi-networking APIs. These let your app
dynamically scan for available networks with specific capabilities, and
establish a connection to them. This is useful when your app requires a
specialized network, such as an SUPL, MMS, or carrier-billing network, or if
you want to send data using a particular type of transport protocol.</p>
-<p>To select and connect to a network dynamically from your app, first
-instantiate a {@code android.net.ConnectivityManager}. Next, create a
-{@code android.net.NetworkRequest} to specify the network features and transport
-type your app is interested in. To start scanning for suitable networks, call
-{@code ConnectivityManager.requestNetwork()} or
-{@code ConnectivityManager.registerNetworkCallback(), and pass in the
-{@code NetworkRequest} object and an implementation of
-{@code ConnectivityManager.NetworkCallbackListener}.</p>
+<p>To select and connect to a network dynamically from your app follow these
+steps:</p>
+
+<ol>
+ <li>Create a {@link android.net.ConnectivityManager}.</li>
+ <li>Create a
+ {@code android.net.NetworkRequest} to specify the network features and transport
+ type your app is interested in.</li>
+ <li>To scan for suitable networks, call
+ {@code ConnectivityManager.requestNetwork()} or
+ {@code ConnectivityManager.registerNetworkCallback()}, and pass in the
+ {@code NetworkRequest} object and an implementation of
+ {@code ConnectivityManager.NetworkCallbackListener}.</li>
+
+</ol>
<p>When the system detects a suitable network, it connects to the network and
invokes the {@code NetworkCallbackListener.onAvailable()} callback. You can use
the {@code android.net.Network} object from the callback to get additional
-information about the network, or to establish a socket connection.</p>
+information about the network, or to direct traffic to use the selected
+network.</p>
<h3 id="BluetoothBroadcasting">Bluetooth broadcasting</h3>
<p>Android 4.3 introduced platform support for <a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html">Bluetooth Low Energy</a>
(BLE) in the central role. In the L Developer Preview, an Android device can now
-act as a Bluetooth LE <em>peripheral device</em> and make its presence known to
+act as a Bluetooth LE <em>peripheral device</em>. Apps can use this capability
+to make their presence known to
nearby devices. For instance, you can build apps that allow a device to
function as a pedometer or health monitor and communicate its data with another
BLE device.</p>
@@ -429,16 +549,19 @@
You must add the {@code android.permission.BLUETOOTH_ADMIN} permission in your
manifest in order for your app to use the new advertising and scanning features.</a>
-<p>To begin Bluetooth LE advertising so that other devices can discover the
-device running your app, call {@code android.bluetooth.le.BluetoothAdvertiser.startAdvisertising()} and pass in an implementation of the
-{@code android.bluetooth.le.AdvertiseCallback} class to report the success
-or failure of the advertising operation.</p>
+<p>To begin Bluetooth LE advertising so that other devices can discover
+your app, call {@code android.bluetooth.le.BluetoothAdvertiser.startAdvisertising()}
+and pass in an implementation of the
+{@code android.bluetooth.le.AdvertiseCallback} class. The callback object
+receives a report of the success or failure of the advertising operation.</p>
-<p>Conversely, if you want to scan for Bluetooth LE devices nearby, call
-{@code android.bluetooth.le.BluetoothLeScanner.startScan()} and pass in an
+<p> The L Developer Preview introduces the {@code
+android.bluetooth.le.ScanFilter} class so that your app can scan for only the
+specific types of devices it is interested in. To begin scanning for Bluetooth
+LE devices, call {@code android.bluetooth.le.BluetoothLeScanner.startScan()} and
+pass in a list of filters. In the method call, you must also provide an
implementation of {@code android.bluetooth.le.ScanCallback} to report if a
-Bluetooth LE advertisement is found. Optionally, you can pass in filters to scan
-for a specific type of device.</p>
+Bluetooth LE advertisement is found. </p>
<h3 id="NFCEnhancements">NFC enhancements</h3>
<p>The L Developer Preview adds these enhancements to enable wider and more
@@ -446,13 +569,12 @@
<ul>
<li>Android Beam is now available in the share menu.
-<li>Support for the <a href="http://www.wi-fi.org/discover-wi-fi/wi-fi-direct">Wi-fi Direct standard</a>.
<li>Your app can invoke the Android Beam on the user’s device to share data by
calling {@code android.nfc.NfcAdapter.invokeBeam()}. This avoids the need for
the user to manually tap the device against another NFC-capable device to
complete the data transfer.
-<li>Use the new {@code android.nfc.NdefRecord.createTextRecord()} method if
- you want to create an NDEF record containing UTF-8 text data.
+<li>You can use the new {@code android.nfc.NdefRecord.createTextRecord()} method
+to create an NDEF record containing UTF-8 text data.
<li>If you are developing a payment app, you now have the ability to
register an NFC application ID (AID) dynamically by calling
{@code android.nfc.cardemulation.CardEmulation.registerAidsForService()}.
@@ -466,18 +588,31 @@
<h3 id="JobScheduler">Scheduling jobs</h3>
<p>The L Developer Preview provides a new {@code android.app.job.JobScheduler}
API that lets you optimize battery life by defining jobs for the system to run
-asynchronously at a later time, such as when the device is charging. This is
-useful when you want to defer non user-facing units of work, have application
-code that accesses the network, or want to run a number of tasks as a batch on
-a regular schedule.</p>
+asynchronously at a later time or under specified conditions (such as when the
+device is charging). This is useful in such situations as:</p>
+<ul>
+ <li>The app has non-user-facing work that you want to defer until the unit is
+ plugged in.</li>
+ <li>The app has a task that requires network access (or requires a wifi
+ connection).</li>
+ <li>The app has a number of tasks that you want to run as a batch on a regular
+ schedule.</li>
-<p>A {@code android.app.job.JobInfo} object encapsulates such a unit of work,
-and provides an exact description of the criteria you are scheduling.</p>
+</ul>
+
+<p>A unit of work is encapsulated by a {@code android.app.job.JobInfo} object.
+This object provides an exact description of the criteria to be used for
+scheduling.</p>
<p>Use the {@code android.app.job.JobInfo.Builder} to configure how the
scheduled task should run. You can schedule the task to run under specific
-conditions such as only while the device is charging, when connected to an
-unmetered network, or when the system deems the device is idle.</p>
+conditions, such as:</p>
+
+<ul>
+ <li>The device is charging</li>
+ <li>The device is connected to an unmetered network</li>
+ <li>The system deems the device to be idle</li>
+</ul>
<p>For example, you can add code like this to run your task on an
unmetered network:</p>
@@ -513,23 +648,33 @@
</ul>
<p>Use the {@code --help} option to learn about the various options for
-tailoring the output. For example, to run the tool to print battery usage
-statistics since the device was last charged for a given app package, run this
+tailoring the output. For example, to print battery usage
+statistics for a given app package since the device was last charged, run this
command:
<pre>
-$ adb shell dumpsys batterystats --charged <package-name>
+$ adb shell dumpsys batterystats --charged <package-name>
</pre>
</dd>
<dt><strong>Battery Historian</strong></dt>
<dd>
-<p>The Battery Historian tool ({@code historian.par}) analyzes L-based Android
-bug reports and creates an HTML visualization of power-related events. It can
-also visualize power consumption data from a power monitor, and will attempt to
-map power usage to the wakelocks seen. You can find the Battery Historian tool
+<p>The Battery Historian tool ({@code historian.par}) analyzes Android
+bug reports from the L Developer Preview and creates an HTML visualization of
+power-related events. It can
+also visualize power consumption data from a power monitor, and attempts to
+map power usage to the wake locks seen. You can find the Battery Historian tool
in {@code <sdk>/tools}.</p>
-<p>For best results, you should first enable full wakelock reporting to allow
+<img src="images/battery_historian.png"
+ srcset="images/battery_historian@2x.png 2x"
+ alt="" width="440" height="240"
+ id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1.</strong>HTML visualization generated by the Battery
+ Historian tool.
+</p>
+
+<p>For best results, you should first enable full wake lock reporting, to allow
the Battery Historian tool to monitor uninterrupted over an extended period of
time:</p>
<pre>
@@ -548,93 +693,70 @@
</pre>
</dd>
-<dt><strong>On-device power management</strong></dt>
-<dd>
-<p>You can use the {@code android.os.BatteryManager} API to obtain power
-consumption information based on the battery fuel gauge included in Android
-phones and tablets. This is useful in cases when it is not convenient to
-connect external measurement equipment to the Android device.</p>
-<p>To retrieve the battery properties, call {@code BatteryManager.getIntProperty()}
-or {@code BatteryManager.getLongProperty()}. The properties available, the
-exact resolution of the values of each, and other characteristics such as
-update frequency depend on the particular device being tested.</p>
-
-<p>The following properties can be inspected on all Android devices:</p>
-
-<table>
- <tr>
- <th>Property</th>
- <th>Description</th>
- </tr>
- <tr>
- <td>{@code BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER}</td>
- <td>Remaining battery capacity in microampere-hours.</td>
- </tr>
- <tr>
- <td>{@code BatteryManager.BATTERY_PROPERTY_CURRENT_NOW}</td>
- <td>Instantaneous battery current in microamperes.</td>
- </tr>
- <tr>
- <td>{@code BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE}</td>
- <td>Average battery current in microamperes</td>
- </tr>
- <tr>
- <td>{@code BatteryManager.BATTERY_PROPERTY_CAPACITY}</td>
- <td>Remaining battery capacity as an integer percentage.</td>
- </tr>
- <tr>
- <td>{@code BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER}</td>
- <td>Remaining energy in nanowatt-hours.</td>
- </tr>
-</table>
-<dd>
</dl>
<h2 id="Enterprise">Enterprise</h2>
<h3 id="ManagedProvisioning">Managed provisioning</h3>
+<div class="figure" style="width:360px">
+ <img src="images/managed_apps_launcher.png"
+ srcset="images/managed_apps_launcher@2x.png 2x"
+ alt="" width="360" height="572" id="figure2" />
+ <p class="img-caption">
+ <strong>Figure 2.</strong> Launcher screen showing managed apps (marked with
+ a lock badge)
+ </p>
+</div>
+
<p>The L Developer Preview provides new functionality for running apps within
an enterprise environment:</p>
<ul>
<li><strong>Create managed user profiles</strong>. A device administrator can
-initiate a managed provisioning process to enroll a user device with an
-existing personal account into a co-present but separate managed profile that
-the administrator controls.
-<li><strong>Set device owner scope</strong>. Device administrators can also
-apply managed provisioning to configure a device that has no previous user
-accounts installed, so that they have full control over the device.
+initiate a managed provisioning process to add a co-present but separate managed
+profile to a device with an existing personal account. The administrator has
+control over the managed profile.</li>
+<li><strong>Set device owner</strong>. Device administrators can also initiate a
+managed provisioning process to automatically provision a
+currently-unprovisioned device such that they have full control over the
+device.</li>
</ul>
-<p>To start the manged provisioning process, send
-{@code ACTION_PROVISION_MANAGED_PROFILE} in an {@link android.content.Intent}. A
-user may be associated with more than one managed profile. To get a list of the
-managed profiles associated with the user, call
-{@code android.os.UserManager.getUserProfiles()}.</p>
+<p>To start the managed provisioning process, send {@code
+ACTION_PROVISION_MANAGED_PROFILE} in an {@link android.content.Intent}. If the
+call is successful, the system triggers the {@code
+android.app.admin.DeviceAdminReceiver. onProfileProvisioningComplete()} callback.
+You can then call {@code app.admin.DevicePolicyManager. setProfileEnabled()} to
+set this profile to the enabled state.</p>
+
+<p>A user may be associated with more than one managed profile. To get a list of
+the managed profiles associated with the user, call
+{@code android.os.UserManager. getUserProfiles()}.</p>
<p>Once a managed profile is created for a user, apps that are managed by the
device administrator will appear alongside non-managed apps in the user’s
-Launcher, Recent apps screen, and notifications. A device policy management app
-can make the managed apps visually prominent by appending a “work” badge to the
-icon drawable with {@code android.os.UserManager.getBadgeDrawableForUser()}.</p>
+Launcher, Recent apps screen, and notifications.</p>
-<p>If you are developing a Launcher app, you can use the new {@code android.content.pm.LauncherApps} class to get a list of launchable activities for the current user
-and any associated managed profiles.</p>
+<p>If you are developing a Launcher app, you can use the new {@code
+android.content.pm.LauncherApps} class to get a list of launchable activities
+for the current user and any associated managed profiles. Your Launcher can make
+the managed apps visually prominent by appending a “work” badge to the icon
+drawable with {@code android.os.UserManager.getBadgeDrawableForUser()}.</p>
<h2 id="Printing">Printing Framework</h2>
<h3 id="PDFRender">Render PDF as bitmap</h3>
<p>You can now render PDF document pages into bitmap images for printing by
using the new {@code android.graphics.pdf.PdfRenderer} class. You must specify a
-{@code ParcelFileDescriptor} that is seekable (that is, the file can be randomly
+{@link android.os.ParcelFileDescriptor} that is seekable (that is, the content can be randomly
accessed) on which the system writes the the printable content. Your app can
obtain a page for rendering with {@code openPage()}, then call {@code render()}
to turn the opened {@code PdfRenderer.Page} into a bitmap. You can also set
-additional parameters if you only wan to convert a portion of the document into
+additional parameters if you only want to convert a portion of the document into
a bitmap image (for example, to implement <a href="http://en.wikipedia.org/wiki/Tiled_rendering">tile rendering</a> in order to zoom in on the document).</p>
<h2 id="TestingA11y">Testing & Accessibility </h2>
-<h3 id="Testing A11yImprovements">Testing and accessibility improvements</h3>
+<h3 id="TestingA11yImprovements">Testing and accessibility improvements</h3>
<p>The L Developer Preview adds the following support for testing and
accessibility:</p>
@@ -644,44 +766,45 @@
capture frame statistics for window animations and content. This lets you
write instrumentation tests to evaluate if the app under test is rendering
frames at a sufficient refresh frequency to provide a smooth user experience.
+
<li>You can execute shell commands from your instrumentation test with the new
{@code android.app.UiAutomation.executeShellCommand()}. The command execution
-is similar to running 'adb shell' from a host connected to the device. This
+is similar to running {@code adb shell} from a host connected to the device. This
allows you to use shell based tools such as {@code dumpsys}, {@code am},
{@code content}, and {@code pm}.
+
<li>Accessibility services and test tools that use the accessibility APIs
-(such as <a href="{@docRoot}tools/help/uiautomator/index.html">UiAutomator</a>)
+(such as <a href="{@docRoot}tools/help/uiautomator/index.html">uiautomator</a>)
can now retrieve detailed information about the properties of windows on the
screen that sighted users can interact with. To retrieve a list of
-{@code android.view.accessibility.AccessibilityWindowInfo} representing the
+{@code android.view.accessibility.AccessibilityWindowInfo} objects
+representing the
windows information, call the new
{@code android.accessibilityservice.AccessibilityService.getWindows()} method.
<li>You can use the new {@code android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction} to define standard or customized
-actions to perform on an {@code android.view.accessibility.AccessibilityNodeInfo}.
+actions to perform on an {@link android.view.accessibility.AccessibilityNodeInfo}.
The new {@code AccessibilityAction} class replaces the actions-related APIs
previously found in {@code AccessibilityNodeInfo}.
</ul>
-<h2 id="manifest">Manifest Declarations</h2>
+<h2 id="Manifest">Manifest Declarations</h2>
<h3 id="ManifestFeatures">Declarable required features</h3>
-<p>The following values are now supported in the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> element so you
+<p>The following values are now supported in the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> element, so you
can ensure that your app is installed only on devices that provide the features
your app needs.</p>
<ul>
-<li>{@code FEATURE_LEANBACK}. Declares that your app must be installed only on devices that support the <a href="{@docRoot}tv}">Android TV</a> user interface. Example:
+<li>{@code FEATURE_LEANBACK}. Declares that your app must be installed only on
+devices that support the <a href="{@docRoot}training/tv}">Android TV</a> user
+interface. Example:
<pre>
<uses-feature android:name="android.software.leanback"
android:required="true" />
</pre>
-<li>{@code FEATURE_MANAGEDPROFILES}. Declares that your app must only be installed on devices that support managed profiles for enterprise users. Example:
-<pre>
-<uses-feature android:name="android.software.managedprofiles"
- android:required="true" />
-</pre>
-<li>{@code FEATURE_WEBVIEW}. Declares that your app must only be installed on devices that fully implement the android.webkit.* APIs. Example:
+<li>{@code FEATURE_WEBVIEW}. Declares that your app must only be installed on
+devices that fully implement the {@code android.webkit.*} APIs. Example:
<pre>
<uses-feature android:name="android.software.webview"
android:required="true" />
diff --git a/docs/html/preview/images/battery_historian.png b/docs/html/preview/images/battery_historian.png
new file mode 100644
index 0000000..5b0db74
--- /dev/null
+++ b/docs/html/preview/images/battery_historian.png
Binary files differ
diff --git a/docs/html/preview/images/battery_historian@2x.png b/docs/html/preview/images/battery_historian@2x.png
new file mode 100644
index 0000000..dbb5d5e
--- /dev/null
+++ b/docs/html/preview/images/battery_historian@2x.png
Binary files differ
diff --git a/docs/html/preview/images/managed_apps_launcher.png b/docs/html/preview/images/managed_apps_launcher.png
new file mode 100644
index 0000000..983d904
--- /dev/null
+++ b/docs/html/preview/images/managed_apps_launcher.png
Binary files differ
diff --git a/docs/html/preview/images/managed_apps_launcher@2.png b/docs/html/preview/images/managed_apps_launcher@2.png
new file mode 100644
index 0000000..d298fd2
--- /dev/null
+++ b/docs/html/preview/images/managed_apps_launcher@2.png
Binary files differ
diff --git a/docs/html/sdk/installing/adding-packages.jd b/docs/html/sdk/installing/adding-packages.jd
index f6435f7..e6c0118 100644
--- a/docs/html/sdk/installing/adding-packages.jd
+++ b/docs/html/sdk/installing/adding-packages.jd
@@ -74,6 +74,11 @@
</li>
</ul>
+<p>When you open the SDK Manager for the first time, several packages will be selected by
+default. Leave these selected, but be sure you have everything you need
+to get started by following these steps:</p>
+
+
<ol class="large">
<li>
<h2 id="GetTools" class="norule">Get the latest SDK tools</h2>
@@ -87,7 +92,7 @@
<ul>
<li><strong>Android SDK Tools</strong></li>
<li><strong>Android SDK Platform-tools</strong></li>
- <li><strong>Android SDK Build-tools</strong></li>
+ <li><strong>Android SDK Build-tools</strong> (highest version)</li>
</ul>
</li>
<li>Open the first Android X.X folder (the latest version) and select:
@@ -97,7 +102,6 @@
<strong>ARM EABI v7a System Image</strong></li>
</ul>
</li>
- <li>Click <strong>Install</strong>.</li>
</ol>
</li>
@@ -105,8 +109,6 @@
<h2 id="GetSupportLib" class="norule">Get the support library for additional APIs</h2>
<div class="sidebox">
- <h3>Why use the support library?</h3>
-
<p>The support library is required for:</p>
<ul>
<li><a href="{@docRoot}wear/index.html">Android Wear</a></li>
@@ -114,7 +116,7 @@
<li><a href="{@docRoot}google/play-services/cast.html">Google Cast</a></li>
</ul>
- <p>The support library also provides these popular APIs:</p>
+ <p>It also provides these popular APIs:</p>
<ul>
<li><a href="{@docRoot}reference/android/support/v4/widget/DrawerLayout.html">Navigation
drawer</a></li>
@@ -127,16 +129,11 @@
<p>The <a href="{@docRoot}tools/support-library/features.html">Android Support Library</a>
provides an extended set of APIs that are compatible with most versions of Android.</p>
- <p>To download the support library:</p>
- <ol>
- <li>Open the <strong>Extras</strong> directory and select:
+ <p>Open the <strong>Extras</strong> directory and select:</p>
<ul>
<li><strong>Android Support Repository</strong></li>
<li><strong>Android Support Library</strong></li>
</ul>
- </li>
- <li>Click <strong>Install</strong>.</li>
- </ol>
<p> </p>
<p> </p>
@@ -148,7 +145,6 @@
<h2 id="GetGoogle" class="norule">Get Google Play services for even more APIs</h2>
<div class="sidebox">
- <h3>Why use Google Play services?</h3>
<p>The Google Play services APIs provide a variety of features and services for your Android
apps, such as:</p>
@@ -163,15 +159,11 @@
</div>
<p>To develop with Google APIs, you need the Google Play services package:</p>
- <ol>
- <li>Open the <strong>Extras</strong> directory and select:
+ <p>Open the <strong>Extras</strong> directory and select:</p>
<ul>
<li><strong>Google Repository</strong></li>
<li><strong>Google Play services</strong></li>
</ul>
- </li>
- <li>Click <strong>Install</strong>.</li>
- </ol>
<p class="note"><strong>Note:</strong> Google Play services APIs are not available on all
Android-powered devices, but are available on all devices with Google Play Store. To use these
@@ -180,6 +172,18 @@
</li>
+<li>
+ <h2 id="Install" class="norule">Install the packages</h2>
+ <p>Once you've selected all the desired packages, continue to install:</p>
+ <ol>
+ <li>Click <strong>Install X packages</strong>.</li>
+ <li>In the next window, double-click each package name on the left
+ to accept the license agreement for each.</li>
+ <li>Click <strong>Install</strong>.</li>
+ </ol>
+ <p>The download progress is shown at the bottom of the SDK Manager window.
+ <strong>Do not exit the SDK Manager</strong> or it will cancel the download.</p>
+</li>
<li>
<h2 id="Build" class="norule">Build something!</h2>
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index b6929bd..3671726 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -108,13 +108,13 @@
your JDK folder, for example <code>C:\Program Files\Java\jdk1.7.0_21</code>.</p>
</p>
</li>
-
+
</ol>
<p>The individual tools and
other SDK packages are saved within the Android Studio application directory.
-To access the tools directly, use a terminal to navigate into the application and locate
+If you need to access the tools directly, use a terminal to navigate into the application and locate
the {@code sdk/} directory. For example:</p>
<p><code>\Users\<user>\AppData\Local\Android\android-studio\sdk\</code></p>
@@ -140,7 +140,7 @@
<p>The individual tools and
other SDK packages are saved within the Android Studio application directory.
-To access the tools directly, use a terminal to navigate into the application and locate
+If you need access the tools directly, use a terminal to navigate into the application and locate
the {@code sdk/} directory. For example:</p>
<p><code>/Applications/Android\ Studio.app/sdk/</code></p>
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index c97afa5..8ac6163 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -339,18 +339,12 @@
</tr>
<tr>
- <td>APK signing</td>
+ <td>APK signing and keystore management</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr>
- <td>Keystore management</td>
- <td class="no">Coming soon</td>
- <td class="yes">Yes</td>
- </tr>
-
- <tr>
<td>NDK support</td>
<td class="no">Coming soon</td>
<td class="yes">Yes</td>
diff --git a/docs/html/tv/images/hero.jpg b/docs/html/tv/images/hero.jpg
index c42a436..e951167 100644
--- a/docs/html/tv/images/hero.jpg
+++ b/docs/html/tv/images/hero.jpg
Binary files differ
diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd
index e1cae8c..3e7652c 100644
--- a/docs/html/tv/index.jd
+++ b/docs/html/tv/index.jd
@@ -4,7 +4,6 @@
no_footer_links=true
page.type=about
-
@jd:body
<style>
@@ -14,17 +13,9 @@
}
</style>
-<style>
-#footer {
- display: none;
-}
-.content-footer {
- display: none;
-}
-</style>
-
<div class="landing-body-content">
+
<div class="landing-hero-container">
<div class="landing-section tv-hero">
@@ -42,9 +33,11 @@
Put your app on TV and bring everyone into
the action.</p>
</div>
+ </div>
<div class="landing-body">
- <a href="{@docRoot}preview/tv/index.html" class="landing-button landing-primary" style="margin-top: 40px;">
+ <a href="{@docRoot}preview/tv/start/index.html" class="landing-button
+ landing-primary" style="margin-top: 40px;">
Get Started
</a>
</div>
@@ -58,11 +51,10 @@
</a>
</div>
</div> <!-- end .landing-section .landing-hero -->
- </div> <!-- end .landing-hero-container -->
<div class="landing-rest-of-page">
- <div class="landing-section landing-gray-background" id="reimagine-your-app">
+ <div class="landing-section" style="background-color:#f5f5f5" id="reimagine-your-app">
<div class="wrap">
<div class="landing-section-header">
<div class="landing-h1">Reimagine Your App</div>
@@ -71,7 +63,6 @@
</div>
</div>
-
<div class="landing-body">
<div class="landing-breakout cols">
@@ -119,13 +110,13 @@
</div> <!-- end .wrap -->
</div> <!-- end .landing-section -->
- <div class="landing-section" style="background-color:#f5f5f5">
+ <div class="landing-section landing-gray-background">
<div class="wrap">
<div class="landing-section-header">
<div class="landing-h1">Build to Entertain</div>
<div class="landing-subhead">
- Android TV let's you engage your users in a new, shared environment.<br>
- Find out how to get your app ready for it's big screen debut.
+ Android TV lets you engage your users in a new, shared environment.<br>
+ Find out how to get your app ready for its big-screen debut.
</div>
</div>
@@ -142,7 +133,7 @@
catalogs.
</p>
<p class="landing-small">
- <a href="{@docRoot}design/tv/index.html">Learn pre-built fragments</a>
+ <a href="{@docRoot}preview/tv/ui/browse.html">Learn pre-built fragments</a>
</p>
</div>
@@ -151,11 +142,10 @@
<p>Get Found</p>
<p class="landing-small">
- Give your content the attention it deserves by including it in Android TV's global
- search results.
+ Help users find your content quickly with in-app searching.
</p>
<p class="landing-small">
- <a href="{@docRoot}design/tv/index.html">Learn about TV design</a>
+ <a href="{@docRoot}preview/tv/ui/in-app-search.html">Learn about app search</a>
</p>
</div>
@@ -167,7 +157,8 @@
Suggest content from your app to keep your users coming back.
</p>
<p class="landing-small">
- <a href="{@docRoot}design/tv/index.html">Learn about design for TV</a>
+ <a href="{@docRoot}preview/tv/ui/recommendations.html">Learn about
+ recommendations</a>
</p>
</div>
@@ -182,28 +173,26 @@
<div class="landing-section-header">
<div class="landing-h1 landing-align-left">Get Started with Android TV</div>
<div class="landing-body">
- <p>You can begin building apps right away using these developer resources.</p>
+ <p>Begin building TV apps right away using these developer resources:</p>
</div>
</div>
<div class="landing-body">
<div class="landing-breakout cols">
- <div class="col-8">
- <p>Preview SDK</p>
+ <div class="col-8" style="margin-left: -8px;">
+ <p style="font-size: 24px;">L-Preview SDK</p>
<p>
- Get started building for Android TV using the Android L-preview SDK. The preview
- SDK includes the Android TV emulator so you can start building your TV app right
- away.
+ The preview SDK includes all the tools you need to build and test apps for TV.
+ Download it and start creating your big-screen app.
</p>
</div>
<div class="col-8">
- <p>ADT-1 Developer Kit</p>
+ <p style="font-size: 24px;">ADT-1 Developer Kit</p>
<p>
- While supplies last, developers can request an ADT-1 Developer Kit, a compact and
- powerful streaming media player and gamepad, ideal for developing apps for Android
- TV.
+ Request an ADT-1 Developer Kit, a compact and powerful streaming media player
+ and gamepad, ideal for developing and testing apps for TV.
</p>
</div>
@@ -215,15 +204,16 @@
<div class="landing-breakout cols">
<div class="col-8">
- <a href="{@docRoot}preview/download.html" class="landing-button landing-secondary">
+ <a href="{@docRoot}preview/setup-sdk.html" class="landing-button landing-secondary">
Download the Preview SDK
</a>
</div>
<div class="col-8">
- <a href="{@docRoot}tv/adt-1/request.html" class="landing-button landing-secondary">
+ <a href="{@docRoot}preview/tv/adt-1/request.html" class="landing-button landing-secondary">
Request ADT-1 Developer Kit
</a>
+ </div>
</div>
</div>
@@ -232,31 +222,33 @@
</div> <!-- end .landing-rest-of-page -->
-
- <div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
- <div class="layout-content-col col-16" style="padding-top:4px">
- <style>#___plusone_0 {float:right !important;}</style>
- <div class="g-plusone" data-size="medium"></div>
+ <div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement"
+ style="border-top: none;">
+ <div class="layout-content-col col-16" style="padding-top:4px">
+ <style>#___plusone_0 {float:right !important;}</style>
+ <div class="g-plusone" data-size="medium"></div>
+ </div>
</div>
- </div>
- <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
- <div id="copyright">
- Except as noted, this content is
- licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
- Creative Commons Attribution 2.5</a>. For details and
- restrictions, see the <a href="/license.html">Content
- License</a>.
+ <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
+ <div id="copyright">
+ Except as noted, this content is
+ licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
+ Creative Commons Attribution 2.5</a>. For details and
+ restrictions, see the <a href="/license.html">Content
+ License</a>.
+ </div>
</div>
- </div>
-
- </div> <!-- end landing-body-content -->
+ </div> <!-- end .landing-hero-container -->
<script>
$("a.landing-down-arrow").on("click", function(e) {
$("body").animate({
- scrollTop: $(".wear-hero").height() + 76
+ scrollTop: $(".tv-hero").height() + 120
}, 1000, "easeOutQuint");
e.preventDefault();
});
</script>
+
+</div> <!-- end landing-body-content -->
+
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index 59d5506..0d9325d 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -66,7 +66,7 @@
</a>
</div>
</div> <!-- end .landing-section .landing-hero -->
- </div> <!-- end .landing-hero-container -->
+
<div class="landing-rest-of-page">
<div class="landing-section" id="extending-android-to-wearables">
@@ -264,7 +264,7 @@
<div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
<div class="layout-content-col col-16" style="padding-top:4px">
<style>#___plusone_0 {float:right !important;}</style>
- <div id="___plusone_0" style="text-indent: 0px; margin: 0px; padding: 0px; border-style: none; float: none; line-height: normal; font-size: 1px; vertical-align: baseline; display: inline-block; width: 90px; height: 20px; background: transparent;"><iframe frameborder="0" hspace="0" marginheight="0" marginwidth="0" scrolling="no" style="position: static; top: 0px; width: 90px; margin: 0px; border-style: none; left: 0px; visibility: visible; height: 20px;" tabindex="0" vspace="0" width="100%" id="I0_1402525433965" name="I0_1402525433965" src="https://apis.google.com/u/0/_/+1/fastbutton?usegapi=1&size=medium&origin=http%3A%2F%2Frobertly.mtv%3A8080&url=http%3A%2F%2Frobertly.mtv%3A8080%2Fwear%2Findex.html&gsrc=3p&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.QxHQHBkhz7M.O%2Fm%3D__features__%2Fam%3DUQ%2Frt%3Dj%2Fd%3D1%2Fz%3Dzcms%2Frs%3DAItRSTMLrMyRVKsu2FQoRingre3w1MT49A#_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe%2C_renderstart%2Concircled%2Cdrefresh%2Cerefresh%2Conload&id=I0_1402525433965&parent=http%3A%2F%2Frobertly.mtv%3A8080&pfname=&rpctoken=32453860" data-gapiattached="true" title="+1"></iframe></div>
+ <div class="g-plusone" data-size="medium"></div>
</div>
</div>
<div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
@@ -276,5 +276,16 @@
License</a>.
</div>
</div>
- </div> <!-- end landing-body-content -->
+ </div> <!-- end .landing-hero-container -->
+
+ <script>
+ $("a.landing-down-arrow").on("click", function(e) {
+ $("body").animate({
+ scrollTop: $(".wear-hero").height() + 120
+ }, 1000, "easeOutQuint");
+ e.preventDefault();
+ });
+ </script>
+
+</div> <!-- end landing-body-content -->
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 2b36016..158801c 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1091,7 +1091,15 @@
if (oval == null) {
throw new NullPointerException();
}
- native_drawOval(mNativeCanvasWrapper, oval, paint.mNativePaint);
+ drawOval(oval.left, oval.top, oval.right, oval.bottom, paint);
+ }
+
+ /**
+ * Draw the specified oval using the specified paint. The oval will be
+ * filled or framed based on the Style in the paint.
+ */
+ public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) {
+ native_drawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint);
}
/**
@@ -1133,10 +1141,34 @@
*/
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
@NonNull Paint paint) {
- if (oval == null) {
- throw new NullPointerException();
- }
- native_drawArc(mNativeCanvasWrapper, oval, startAngle, sweepAngle,
+ drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
+ paint);
+ }
+
+ /**
+ * <p>Draw the specified arc, which will be scaled to fit inside the
+ * specified oval.</p>
+ *
+ * <p>If the start angle is negative or >= 360, the start angle is treated
+ * as start angle modulo 360.</p>
+ *
+ * <p>If the sweep angle is >= 360, then the oval is drawn
+ * completely. Note that this differs slightly from SkPath::arcTo, which
+ * treats the sweep angle modulo 360. If the sweep angle is negative,
+ * the sweep angle is treated as sweep angle modulo 360</p>
+ *
+ * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
+ * geometric angle of 0 degrees (3 o'clock on a watch.)</p>
+ *
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ * @param useCenter If true, include the center of the oval in the arc, and
+ close it if it is being stroked. This will draw a wedge
+ * @param paint The paint used to draw the arc
+ */
+ public void drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, boolean useCenter, @NonNull Paint paint) {
+ native_drawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
useCenter, paint.mNativePaint);
}
@@ -1908,14 +1940,14 @@
float top, float right,
float bottom,
long nativePaint);
- private static native void native_drawOval(long nativeCanvas, RectF oval,
- long nativePaint);
+ private static native void native_drawOval(long nativeCanvas, float left, float top,
+ float right, float bottom, long nativePaint);
private static native void native_drawCircle(long nativeCanvas, float cx,
float cy, float radius,
long nativePaint);
- private static native void native_drawArc(long nativeCanvas, RectF oval,
- float startAngle, float sweep,
- boolean useCenter,
+ private static native void native_drawArc(long nativeCanvas, float left, float top,
+ float right, float bottom,
+ float startAngle, float sweep, boolean useCenter,
long nativePaint);
private static native void native_drawRoundRect(long nativeCanvas,
float left, float top, float right, float bottom,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 8837955..17ce026 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1532,20 +1532,22 @@
return 0;
}
if (!mHasCompatScaling) {
- return native_breakText(text, index, count, maxWidth, mBidiFlags, measuredWidth);
+ return native_breakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth,
+ mBidiFlags, measuredWidth);
}
final float oldSize = getTextSize();
- setTextSize(oldSize*mCompatScaling);
- int res = native_breakText(text, index, count, maxWidth*mCompatScaling, mBidiFlags,
- measuredWidth);
+ setTextSize(oldSize * mCompatScaling);
+ int res = native_breakText(mNativePaint, mNativeTypeface, text, index, count,
+ maxWidth * mCompatScaling, mBidiFlags, measuredWidth);
setTextSize(oldSize);
if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
return res;
}
- private native int native_breakText(char[] text, int index, int count,
- float maxWidth, int bidiFlags, float[] measuredWidth);
+ private static native int native_breakText(long native_object, long native_typeface,
+ char[] text, int index, int count,
+ float maxWidth, int bidiFlags, float[] measuredWidth);
/**
* Measure the text, stopping early if the measured width exceeds maxWidth.
@@ -1622,19 +1624,21 @@
return 0;
}
if (!mHasCompatScaling) {
- return native_breakText(text, measureForwards, maxWidth, mBidiFlags, measuredWidth);
+ return native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+ maxWidth, mBidiFlags, measuredWidth);
}
final float oldSize = getTextSize();
setTextSize(oldSize*mCompatScaling);
- int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, mBidiFlags,
- measuredWidth);
+ int res = native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+ maxWidth*mCompatScaling, mBidiFlags, measuredWidth);
setTextSize(oldSize);
if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
return res;
}
- private native int native_breakText(String text, boolean measureForwards,
+ private static native int native_breakText(long native_object, long native_typeface,
+ String text, boolean measureForwards,
float maxWidth, int bidiFlags, float[] measuredWidth);
/**
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index c600f47..c40a66d 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -62,7 +62,7 @@
}
mNativePath = init2(valNative);
}
-
+
/**
* Clear any lines and curves from the path, making it empty.
* This does NOT change the fill-type setting.
@@ -205,7 +205,7 @@
* Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
*/
INVERSE_EVEN_ODD(3);
-
+
FillType(int ni) {
nativeInt = ni;
}
@@ -425,7 +425,7 @@
* the path is different from the path's current last point, then an
* automatic lineTo() is added to connect the current contour to the
* start of the arc. However, if the path is empty, then we call moveTo()
- * with the first point of the arc. The sweep angle is tread mod 360.
+ * with the first point of the arc.
*
* @param oval The bounds of oval defining shape and size of the arc
* @param startAngle Starting angle (in degrees) where the arc begins
@@ -435,10 +435,9 @@
*/
public void arcTo(RectF oval, float startAngle, float sweepAngle,
boolean forceMoveTo) {
- isSimplePath = false;
- native_arcTo(mNativePath, oval, startAngle, sweepAngle, forceMoveTo);
+ arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo);
}
-
+
/**
* Append the specified arc to the path as a new contour. If the start of
* the path is different from the path's current last point, then an
@@ -451,10 +450,27 @@
* @param sweepAngle Sweep angle (in degrees) measured clockwise
*/
public void arcTo(RectF oval, float startAngle, float sweepAngle) {
- isSimplePath = false;
- native_arcTo(mNativePath, oval, startAngle, sweepAngle, false);
+ arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false);
}
-
+
+ /**
+ * Append the specified arc to the path as a new contour. If the start of
+ * the path is different from the path's current last point, then an
+ * automatic lineTo() is added to connect the current contour to the
+ * start of the arc. However, if the path is empty, then we call moveTo()
+ * with the first point of the arc.
+ *
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
+ * mod 360.
+ * @param forceMoveTo If true, always begin a new contour with the arc
+ */
+ public void arcTo(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, boolean forceMoveTo) {
+ isSimplePath = false;
+ native_arcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
+ }
+
/**
* Close the current contour. If the current point is not equal to the
* first point of the contour, a line segment is automatically added.
@@ -473,13 +489,13 @@
CW (1), // must match enum in SkPath.h
/** counter-clockwise */
CCW (2); // must match enum in SkPath.h
-
+
Direction(int ni) {
nativeInt = ni;
}
final int nativeInt;
}
-
+
private void detectSimplePath(float left, float top, float right, float bottom, Direction dir) {
if (mLastDirection == null) {
mLastDirection = dir;
@@ -557,11 +573,19 @@
* @param sweepAngle Sweep angle (in degrees) measured clockwise
*/
public void addArc(RectF oval, float startAngle, float sweepAngle) {
- if (oval == null) {
- throw new NullPointerException("need oval parameter");
- }
+ addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
+ }
+
+ /**
+ * Add the specified arc to the path as a new contour.
+ *
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ */
+ public void addArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle) {
isSimplePath = false;
- native_addArc(mNativePath, oval, startAngle, sweepAngle);
+ native_addArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle);
}
/**
@@ -573,13 +597,22 @@
* @param dir The direction to wind the round-rectangle's contour
*/
public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
- isSimplePath = false;
- native_addRoundRect(mNativePath, rect, rx, ry, dir.nativeInt);
+ addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, dir);
}
-
+
+ /**
+ * Add a closed round-rectangle contour to the path
+ *
+ * @param rx The x-radius of the rounded corners on the round-rectangle
+ * @param ry The y-radius of the rounded corners on the round-rectangle
+ * @param dir The direction to wind the round-rectangle's contour
+ */
+ public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ Direction dir) {
+ isSimplePath = false;
+ native_addRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt);
+ }
+
/**
* Add a closed round-rectangle contour to the path. Each corner receives
* two radius values [X, Y]. The corners are ordered top-left, top-right,
@@ -593,13 +626,26 @@
if (rect == null) {
throw new NullPointerException("need rect parameter");
}
+ addRoundRect(rect.left, rect.top, rect.right, rect.bottom, radii, dir);
+ }
+
+ /**
+ * Add a closed round-rectangle contour to the path. Each corner receives
+ * two radius values [X, Y]. The corners are ordered top-left, top-right,
+ * bottom-right, bottom-left
+ *
+ * @param radii Array of 8 values, 4 pairs of [X,Y] radii
+ * @param dir The direction to wind the round-rectangle's contour
+ */
+ public void addRoundRect(float left, float top, float right, float bottom, float[] radii,
+ Direction dir) {
if (radii.length < 8) {
throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
}
isSimplePath = false;
- native_addRoundRect(mNativePath, rect, radii, dir.nativeInt);
+ native_addRoundRect(mNativePath, left, top, right, bottom, radii, dir.nativeInt);
}
-
+
/**
* Add a copy of src to the path, offset by (dx,dy)
*
@@ -755,19 +801,24 @@
float x2, float y2, float x3, float y3);
private static native void native_rCubicTo(long nPath, float x1, float y1,
float x2, float y2, float x3, float y3);
- private static native void native_arcTo(long nPath, RectF oval,
- float startAngle, float sweepAngle, boolean forceMoveTo);
+ private static native void native_arcTo(long nPath, float left, float top,
+ float right, float bottom, float startAngle,
+ float sweepAngle, boolean forceMoveTo);
private static native void native_close(long nPath);
private static native void native_addRect(long nPath, float left, float top,
float right, float bottom, int dir);
private static native void native_addOval(long nPath, float left, float top,
float right, float bottom, int dir);
private static native void native_addCircle(long nPath, float x, float y, float radius, int dir);
- private static native void native_addArc(long nPath, RectF oval,
- float startAngle, float sweepAngle);
- private static native void native_addRoundRect(long nPath, RectF rect,
+ private static native void native_addArc(long nPath, float left, float top,
+ float right, float bottom,
+ float startAngle, float sweepAngle);
+ private static native void native_addRoundRect(long nPath, float left, float top,
+ float right, float bottom,
float rx, float ry, int dir);
- private static native void native_addRoundRect(long nPath, RectF r, float[] radii, int dir);
+ private static native void native_addRoundRect(long nPath, float left, float top,
+ float right, float bottom,
+ float[] radii, int dir);
private static native void native_addPath(long nPath, long src, float dx, float dy);
private static native void native_addPath(long nPath, long src);
private static native void native_addPath(long nPath, long src, long matrix);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index cb88e3d..40b55a7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1260,8 +1260,10 @@
/**
* Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
* attribute's enum value.
+ *
+ * @hide
*/
- static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
+ public static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
switch (value) {
case 3: return Mode.SRC_OVER;
case 5: return Mode.SRC_IN;
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 91dda75..1b3f1fd 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -1768,6 +1768,7 @@
}
mergeInfoLocked(pMergedInfo, pContents);
+ delete pContents;
return true;
}
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 1cb87f2..8b32c40 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -33,6 +33,7 @@
}
enum TransformType {
+ TransformInvalid = 0,
TransformRenderNode,
TransformMatrix4,
TransformNone,
@@ -56,6 +57,7 @@
memset(mHead, 0, sizeof(DirtyStack));
// Create a root that we will not pop off
mHead->prev = mHead;
+ mHead->type = TransformNone;
}
void DamageAccumulator::pushCommon() {
@@ -100,6 +102,8 @@
case TransformNone:
mHead->pendingDirty.join(dirtyFrame->pendingDirty);
break;
+ default:
+ LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
}
}
@@ -166,9 +170,12 @@
}
const RenderProperties& props = frame->renderNode->properties();
+ if (props.getAlpha() <= 0) {
+ return;
+ }
// Perform clipping
- if (props.getClipToBounds() && !frame->pendingDirty.isEmpty()) {
+ if (props.getClipDamageToBounds() && !frame->pendingDirty.isEmpty()) {
if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
frame->pendingDirty.setEmpty();
}
@@ -186,8 +193,6 @@
if (projectionReceiver) {
applyTransforms(frame, projectionReceiver);
projectionReceiver->pendingDirty.join(frame->pendingDirty);
- } else {
- ALOGW("Failed to find projection receiver? Dropping on the floor...");
}
frame->pendingDirty.setEmpty();
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 59e15e13..310b107 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -57,17 +57,26 @@
#define ROUND_CAP_THRESH 0.25f
#define PI 3.1415926535897932f
+// temporary error thresholds
+#define ERROR_DEPTH 20
+#define ERROR_SCALE 1e10
+#define ERROR_SQR_INV_THRESH 1e-20
+
void PathTessellator::extractTessellationScales(const Matrix4& transform,
float* scaleX, float* scaleY) {
- *scaleX = 1.0f;
- *scaleY = 1.0f;
- if (CC_UNLIKELY(!transform.isPureTranslate())) {
+ if (CC_LIKELY(transform.isPureTranslate())) {
+ *scaleX = 1.0f;
+ *scaleY = 1.0f;
+ } else {
float m00 = transform.data[Matrix4::kScaleX];
float m01 = transform.data[Matrix4::kSkewY];
float m10 = transform.data[Matrix4::kSkewX];
float m11 = transform.data[Matrix4::kScaleY];
*scaleX = sqrt(m00 * m00 + m01 * m01);
*scaleY = sqrt(m10 * m10 + m11 * m11);
+
+ LOG_ALWAYS_FATAL_IF(*scaleX > ERROR_SCALE || *scaleY > ERROR_SCALE,
+ "scales %e x %e too large for tessellation", *scaleX, *scaleY);
}
}
@@ -92,10 +101,12 @@
public:
PaintInfo(const SkPaint* paint, const mat4& transform) :
style(paint->getStyle()), cap(paint->getStrokeCap()), isAA(paint->isAntiAlias()),
- inverseScaleX(1.0f), inverseScaleY(1.0f),
halfStrokeWidth(paint->getStrokeWidth() * 0.5f), maxAlpha(1.0f) {
// compute inverse scales
- if (CC_UNLIKELY(!transform.isPureTranslate())) {
+ if (CC_LIKELY(transform.isPureTranslate())) {
+ inverseScaleX = 1.0f;
+ inverseScaleY = 1.0f;
+ } else {
float scaleX, scaleY;
PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY);
inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
@@ -922,6 +933,9 @@
Vector<Vertex>& outputVertices) {
ATRACE_CALL();
+ LOG_ALWAYS_FATAL_IF(sqrInvScaleX < ERROR_SQR_INV_THRESH || sqrInvScaleY < ERROR_SQR_INV_THRESH,
+ "Invalid scale factors used for approx %e, %e", sqrInvScaleX, sqrInvScaleY);
+
// TODO: to support joins other than sharp miter, join vertices should be labelled in the
// perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case.
SkPath::Iter iter(path, forceClose);
@@ -975,14 +989,14 @@
// Bezier approximation
///////////////////////////////////////////////////////////////////////////////
-// Depth at which recursion is aborted
-#define ABORT_DEPTH 20
-
void PathTessellator::recursiveCubicBezierVertices(
float p1x, float p1y, float c1x, float c1y,
float p2x, float p2y, float c2x, float c2y,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
Vector<Vertex>& outputVertices, int depth) {
+ LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR DEPTH exceeded: cubic approx, invscale %e x %e, vertcount %d",
+ sqrInvScaleX, sqrInvScaleY, outputVertices.size());
+
float dx = p2x - p1x;
float dy = p2y - p1y;
float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
@@ -990,8 +1004,7 @@
float d = d1 + d2;
// multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
-
- if (depth >= ABORT_DEPTH || d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
+ if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
// below thresh, draw line by adding endpoint
pushToVector(outputVertices, p2x, p2y);
} else {
@@ -1029,11 +1042,14 @@
float cx, float cy,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
Vector<Vertex>& outputVertices, int depth) {
+ LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR_DEPTH exceeded: quadratic approx, invscale %e x %e, vertcount %d",
+ sqrInvScaleX, sqrInvScaleY, outputVertices.size());
+
float dx = bx - ax;
float dy = by - ay;
float d = (cx - bx) * dy - (cy - by) * dx;
- if (depth >= ABORT_DEPTH || d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
+ if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
// below thresh, draw line by adding endpoint
pushToVector(outputVertices, bx, by);
} else {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 378183a..05f4edf 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -117,8 +117,8 @@
}
void RenderNode::damageSelf(TreeInfo& info) {
- if (isRenderable() && properties().getAlpha() > 0) {
- if (properties().getClipToBounds()) {
+ if (isRenderable()) {
+ if (properties().getClipDamageToBounds()) {
info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
} else {
// Hope this is big enough?
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 8c6cc9e..227d56e 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -21,6 +21,7 @@
#include <vector>
#include <cutils/compiler.h>
#include <androidfw/ResourceTypes.h>
+#include <utils/Log.h>
#include <SkCamera.h>
#include <SkMatrix.h>
@@ -30,6 +31,7 @@
#include "Rect.h"
#include "RevealClip.h"
#include "Outline.h"
+#include "utils/MathUtils.h"
class SkBitmap;
class SkColorFilter;
@@ -281,6 +283,7 @@
}
bool setScaleX(float scaleX) {
+ LOG_ALWAYS_FATAL_IF(scaleX > 1000000, "invalid scaleX %e", scaleX);
return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
}
@@ -289,6 +292,7 @@
}
bool setScaleY(float scaleY) {
+ LOG_ALWAYS_FATAL_IF(scaleY > 1000000, "invalid scaleY %e", scaleY);
return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
}
@@ -526,6 +530,15 @@
return mLayerProperties;
}
+ // Returns true if damage calculations should be clipped to bounds
+ // TODO: Figure out something better for getZ(), as children should still be
+ // clipped to this RP's bounds. But as we will damage -INT_MAX to INT_MAX
+ // for this RP's getZ() anyway, this can be optimized when we have a
+ // Z damage estimate instead of INT_MAX
+ bool getClipDamageToBounds() const {
+ return getClipToBounds() && (getZ() <= 0 || getOutline().isEmpty());
+ }
+
private:
// Rendering properties
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 440f965..dc1951b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -537,9 +537,12 @@
requireGlContext();
mode = DrawGlInfo::kModeProcess;
}
- (*functor)(mode, NULL);
if (mCanvas) {
+ mCanvas->interrupt();
+ }
+ (*functor)(mode, NULL);
+ if (mCanvas) {
mCanvas->resume();
}
}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index f70110c..bdd1195 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -583,7 +583,8 @@
}
/**
- * Get the altitude if available, in meters above sea level.
+ * Get the altitude if available, in meters above the WGS 84 reference
+ * ellipsoid.
*
* <p>If this location does not have an altitude then 0.0 is returned.
*/
@@ -592,7 +593,7 @@
}
/**
- * Set the altitude, in meters above sea level.
+ * Set the altitude, in meters above the WGS 84 reference ellipsoid.
*
* <p>Following this call {@link #hasAltitude} will return true.
*/
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 7ff2c2e..3f0405d 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -144,15 +144,41 @@
/**
* Builds a URI that points to all programs on a given channel.
*
+ * @param channelId The ID of the channel to return programs for.
+ */
+ public static final Uri buildProgramsUriForChannel(long channelId) {
+ return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
+ .appendPath(PATH_CHANNEL).appendPath(String.valueOf(channelId))
+ .appendPath(PATH_PROGRAM).build();
+ }
+
+ /**
+ * Builds a URI that points to all programs on a given channel.
+ *
* @param channelUri The URI of the channel to return programs for.
*/
public static final Uri buildProgramsUriForChannel(Uri channelUri) {
if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
throw new IllegalArgumentException("Not a channel: " + channelUri);
}
- String channelId = String.valueOf(ContentUris.parseId(channelUri));
- return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
- .appendPath(PATH_CHANNEL).appendPath(channelId).appendPath(PATH_PROGRAM).build();
+ return buildProgramsUriForChannel(ContentUris.parseId(channelUri));
+ }
+
+ /**
+ * Builds a URI that points to programs on a specific channel whose schedules overlap with the
+ * given time frame.
+ *
+ * @param channelId The ID of the channel to return programs for.
+ * @param startTime The start time used to filter programs. The returned programs should have
+ * {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
+ * @param endTime The end time used to filter programs. The returned programs should have
+ * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
+ */
+ public static final Uri buildProgramsUriForChannel(long channelId, long startTime,
+ long endTime) {
+ Uri uri = buildProgramsUriForChannel(channelId);
+ return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime))
+ .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build();
}
/**
@@ -167,9 +193,10 @@
*/
public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
long endTime) {
- Uri uri = buildProgramsUriForChannel(channelUri);
- return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime))
- .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build();
+ if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
+ throw new IllegalArgumentException("Not a channel: " + channelUri);
+ }
+ return buildProgramsUriForChannel(ContentUris.parseId(channelUri), startTime, endTime);
}
/**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index edfdd60..daa7009 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -533,12 +533,11 @@
/**
* Releases this session.
- *
- * @throws IllegalStateException if the session has been already released.
*/
public void release() {
if (mToken == null) {
- throw new IllegalStateException("the session has been already released");
+ Log.w(TAG, "The session has been already released");
+ return;
}
try {
mService.releaseSession(mToken, mUserId);
@@ -553,12 +552,12 @@
* Sets the {@link android.view.Surface} for this session.
*
* @param surface A {@link android.view.Surface} used to render video.
- * @throws IllegalStateException if the session has been already released.
* @hide
*/
public void setSurface(Surface surface) {
if (mToken == null) {
- throw new IllegalStateException("the session has been already released");
+ Log.w(TAG, "The session has been already released");
+ return;
}
// surface can be null.
try {
@@ -573,11 +572,11 @@
*
* @param volume A volume value between 0.0f to 1.0f.
* @throws IllegalArgumentException if the volume value is out of range.
- * @throws IllegalStateException if the session has been already released.
*/
public void setStreamVolume(float volume) {
if (mToken == null) {
- throw new IllegalStateException("the session has been already released");
+ Log.w(TAG, "The session has been already released");
+ return;
}
try {
if (volume < 0.0f || volume > 1.0f) {
@@ -594,14 +593,14 @@
*
* @param channelUri The URI of a channel.
* @throws IllegalArgumentException if the argument is {@code null}.
- * @throws IllegalStateException if the session has been already released.
*/
public void tune(Uri channelUri) {
if (channelUri == null) {
throw new IllegalArgumentException("channelUri cannot be null");
}
if (mToken == null) {
- throw new IllegalStateException("the session has been already released");
+ Log.w(TAG, "The session has been already released");
+ return;
}
try {
mService.tune(mToken, channelUri, mUserId);
@@ -620,8 +619,7 @@
* @param view A view playing TV.
* @param frame A position of the overlay view.
* @throws IllegalArgumentException if any of the arguments is {@code null}.
- * @throws IllegalStateException if {@code view} is not attached to a window or
- * if the session has been already released.
+ * @throws IllegalStateException if {@code view} is not attached to a window.
*/
void createOverlayView(View view, Rect frame) {
if (view == null) {
@@ -634,7 +632,8 @@
throw new IllegalStateException("view must be attached to a window");
}
if (mToken == null) {
- throw new IllegalStateException("the session has been already released");
+ Log.w(TAG, "The session has been already released");
+ return;
}
try {
mService.createOverlayView(mToken, view.getWindowToken(), frame, mUserId);
@@ -648,14 +647,14 @@
*
* @param frame A new position of the overlay view.
* @throws IllegalArgumentException if the arguments is {@code null}.
- * @throws IllegalStateException if the session has been already released.
*/
void relayoutOverlayView(Rect frame) {
if (frame == null) {
throw new IllegalArgumentException("frame cannot be null");
}
if (mToken == null) {
- throw new IllegalStateException("the session has been already released");
+ Log.w(TAG, "The session has been already released");
+ return;
}
try {
mService.relayoutOverlayView(mToken, frame, mUserId);
@@ -666,12 +665,11 @@
/**
* Removes the current overlay view.
- *
- * @throws IllegalStateException if the session has been already released.
*/
void removeOverlayView() {
if (mToken == null) {
- throw new IllegalStateException("the session has been already released");
+ Log.w(TAG, "The session has been already released");
+ return;
}
try {
mService.removeOverlayView(mToken, mUserId);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 8a7e642..7dba21d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -22,7 +22,6 @@
import android.hardware.ICameraServiceListener;
import android.hardware.IProCameraCallbacks;
import android.hardware.IProCameraUser;
-import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.impl.CameraMetadataNative;
@@ -51,8 +50,14 @@
* </pre>
*/
public class CameraBinderTest extends AndroidTestCase {
+ private static final int MAX_PARAMETERS_LENGTH = 100;
+
static String TAG = "CameraBinderTest";
+ // From ICameraService.h
+ private static final int API_VERSION_1 = 1;
+ private static final int API_VERSION_2 = 2;
+
protected CameraBinderTestUtils mUtils;
public CameraBinderTest() {
@@ -95,6 +100,56 @@
}
}
+ @SmallTest
+ public void testGetLegacyParameters() throws Exception {
+ for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+ String[] parameters = new String[1];
+ assertEquals("Camera service returned parameters for camera " + cameraId,
+ CameraBinderTestUtils.NO_ERROR,
+ mUtils.getCameraService().getLegacyParameters(cameraId, /*out*/parameters));
+ assertNotNull(parameters[0]);
+ assertTrue("Parameters should have at least one character in it",
+ parameters[0].length() > 0);
+
+ int end = parameters[0].length();
+ if (end > MAX_PARAMETERS_LENGTH) {
+ end = MAX_PARAMETERS_LENGTH;
+ }
+
+ Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters[0].substring(0, end));
+ }
+ }
+
+ /** The camera2 api is only supported on HAL3.2+ devices */
+ @SmallTest
+ public void testSupportsCamera2Api() throws Exception {
+ for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+ int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
+
+ if (res != CameraBinderTestUtils.NO_ERROR && res != CameraBinderTestUtils.EOPNOTSUPP) {
+ fail("Camera service returned bad value when queried if it supports camera2 api: "
+ + res + " for camera ID " + cameraId);
+ }
+
+ boolean supports = res == CameraBinderTestUtils.NO_ERROR;
+ Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports);
+ }
+ }
+
+ /** The camera1 api is supported on *all* devices regardless of HAL version */
+ @SmallTest
+ public void testSupportsCamera1Api() throws Exception {
+ for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+ int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
+ assertEquals(
+ "Camera service returned bad value when queried if it supports camera1 api: "
+ + res + " for camera ID " + cameraId, CameraBinderTestUtils.NO_ERROR, res);
+ }
+ }
+
static abstract class DummyBase extends Binder implements android.os.IInterface {
@Override
public IBinder asBinder() {
@@ -158,6 +213,7 @@
* android.hardware.camera2.ICameraDeviceCallbacks#onCameraError(int,
* android.hardware.camera2.CaptureResultExtras)
*/
+ @Override
public void onCameraError(int errorCode, CaptureResultExtras resultExtras)
throws RemoteException {
// TODO Auto-generated method stub
@@ -170,6 +226,7 @@
* android.hardware.camera2.ICameraDeviceCallbacks#onCaptureStarted(
* android.hardware.camera2.CaptureResultExtras, long)
*/
+ @Override
public void onCaptureStarted(CaptureResultExtras resultExtras, long timestamp)
throws RemoteException {
// TODO Auto-generated method stub
@@ -183,6 +240,7 @@
* android.hardware.camera2.impl.CameraMetadataNative,
* android.hardware.camera2.CaptureResultExtras)
*/
+ @Override
public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras)
throws RemoteException {
// TODO Auto-generated method stub
@@ -193,6 +251,7 @@
* (non-Javadoc)
* @see android.hardware.camera2.ICameraDeviceCallbacks#onCameraIdle()
*/
+ @Override
public void onCameraIdle() throws RemoteException {
// TODO Auto-generated method stub
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
index 1be2a62..6be538a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
@@ -22,6 +22,7 @@
protected static final int INVALID_OPERATION = -38;
protected static final int ALREADY_EXISTS = -17;
public static final int NO_ERROR = 0;
+ public static final int EOPNOTSUPP = -95;
private final Context mContext;
public CameraBinderTestUtils(Context context) {
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png
index d4fdbf3..17100f7 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_status_gradient.9.png b/packages/SystemUI/res/drawable-hdpi/recents_status_gradient.9.png
new file mode 100644
index 0000000..e969d4c2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_status_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png
index 9fc1a3b..b53bd8f 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_status_gradient.9.png b/packages/SystemUI/res/drawable-mdpi/recents_status_gradient.9.png
new file mode 100644
index 0000000..657f710
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_status_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png
index f38de93..09606f6 100644
--- a/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_status_gradient.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_status_gradient.9.png
new file mode 100644
index 0000000..a444c55
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_status_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png
index 8194605..427cad9 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_status_gradient.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_status_gradient.9.png
new file mode 100644
index 0000000..29cf44b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_status_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_button_bg.xml b/packages/SystemUI/res/drawable/recents_button_bg.xml
new file mode 100644
index 0000000..a4cb088
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_button_bg.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_status_bar_scrim.xml b/packages/SystemUI/res/layout/recents_status_bar_scrim.xml
new file mode 100644
index 0000000..24928d0
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_status_bar_scrim.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|top"
+ android:scaleType="fitXY"
+ android:src="@drawable/recents_status_gradient" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 23f2796..1bab67a 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -32,8 +32,10 @@
android:id="@+id/application_icon"
android:layout_width="@dimen/recents_task_view_application_icon_size"
android:layout_height="@dimen/recents_task_view_application_icon_size"
- android:layout_marginStart="16dp"
- android:layout_gravity="center_vertical|start" />
+ android:layout_marginStart="8dp"
+ android:layout_gravity="center_vertical|start"
+ android:padding="8dp"
+ android:background="@drawable/recents_button_bg" />
<TextView
android:id="@+id/activity_description"
android:layout_width="match_parent"
@@ -56,6 +58,7 @@
android:layout_marginEnd="4dp"
android:layout_gravity="center_vertical|end"
android:padding="18dp"
+ android:background="@drawable/recents_button_bg"
android:visibility="invisible"
android:src="@drawable/recents_dismiss_light" />
</com.android.systemui.recents.views.TaskBarView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index d24d21e..353368b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -63,8 +63,9 @@
<ImageButton android:id="@+id/settings_button"
style="@android:style/Widget.Material.Button.Borderless"
android:layout_toStartOf="@id/multi_user_switch"
- android:layout_width="56dp"
+ android:layout_width="48dp"
android:layout_height="@dimen/status_bar_header_height"
+ android:layout_marginStart="8dp"
android:src="@drawable/ic_settings_24dp"
android:contentDescription="@string/accessibility_desc_quick_settings"/>
@@ -72,7 +73,7 @@
android:layout_width="wrap_content"
android:layout_height="@dimen/status_bar_header_height"
android:layout_toStartOf="@id/multi_user_switch"
- android:layout_marginEnd="4dp"
+ android:layout_marginEnd="2dp"
android:layout_marginStart="16dp"
/>
@@ -117,12 +118,11 @@
android:layout_below="@id/clock"
/>
</RelativeLayout>
-
<com.android.keyguard.CarrierText
android:id="@+id/keyguard_carrier_text"
android:layout_width="match_parent"
android:layout_height="@dimen/status_bar_header_height_keyguard"
- android:layout_marginLeft="8dp"
+ android:layout_marginLeft="16dp"
android:layout_toStartOf="@id/system_icons_container"
android:gravity="center_vertical"
android:ellipsize="marquee"
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 4021f69..71fb8b8 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -243,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Прекарайте пръст наляво, за да включите камерата"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Докато не изключите това"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ гост"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"За една минута"</item>
<item quantity="other" msgid="6924190729213550991">"За %d минути"</item>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b3b4c9b..b1dc302 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -42,7 +42,7 @@
<string name="battery_saver_confirmation_title" msgid="5987726159603849352">"¿Iniciar ahorro de batería?"</string>
<string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
<string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar ahorro de batería"</string>
- <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reducirá el rendimiento del dispositivo.\n\nEsta función estará inhabilitada cuando el dispositivo esté conectado."</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reducirá el rendimiento del dispositivo.\n\nEsta función estará inhabilitada cuando el dispositivo esté enchufado."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ajustes"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 571e9ba..03ac011 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -245,10 +245,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Balayez l\'écran vers la gauche pour accéder à l\'appareil photo"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
<item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index bcb28e9..fcad161 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -245,10 +245,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Balayer l\'écran vers la gauche pour accéder à l\'appareil photo"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
<item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index bd8b829..024be82 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -243,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Prijeđite prstom ulijevo za fotoaparat"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Dok ne isključite"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ gost"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Jednu minutu"</item>
<item quantity="other" msgid="6924190729213550991">"%d min"</item>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index ee8fa8a..4424338 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -32,26 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ծանուցումներ չկան"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
- <!-- no translation found for battery_low_title (6456385927409742437) -->
- <skip />
+ <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցը լիցքաթափվում է"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"մնում է <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
- <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
- <skip />
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Մնաց <xliff:g id="NUMBER">%d%%</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
- <!-- no translation found for invalid_charger_title (3515740382572798460) -->
- <skip />
- <!-- no translation found for invalid_charger_text (5474997287953892710) -->
- <skip />
- <!-- no translation found for battery_low_why (4553600287639198111) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_title (5987726159603849352) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_ok (7283108887345688413) -->
- <skip />
- <!-- no translation found for battery_saver_start_action (7245333922937402896) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_text (8417584516834617662) -->
- <skip />
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB լիցքավորումը չի աջակցվում:"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Օգտագործեք միայն մատակարարի տրամադրած լիցքավորիչը:"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Կարգավորումներ"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Գործարկե՞լ մարտկոցի տնտեսումը:"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Մեկնարկել"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Գործարկել մարտկոցի տնտեսումը"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Մարտկոցի տնտեսումը կնվազեցնի ձեր սարքի կատարողականը՝ մարտկոցն ավելի երկար օգտագործելու համար:\n\nՄարտկոցի տնտեսումը կանջատվի, հենց սարքը միացնեք հոսանքի աղբյուրին:"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Կարգավորումներ"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Ինքնաթիռային ռեժիմ"</string>
@@ -252,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Խցիկի համար սահեցրեք ձախ"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Քանի դեռ չեք անջատել"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Հյուր"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Հյուր"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Մեկ րոպե"</item>
<item quantity="other" msgid="6924190729213550991">"%d րոպե"</item>
@@ -264,10 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Մեկ ժամ"</item>
<item quantity="other" msgid="5408537517529822157">"%d ժամ"</item>
</plurals>
- <!-- no translation found for battery_saver_notification_title (237918726750955859) -->
- <skip />
- <!-- no translation found for battery_saver_notification_text (7796554871101546872) -->
- <skip />
- <!-- no translation found for battery_saver_notification_action_text (7546297220816993504) -->
- <skip />
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Մարտկոցի տնտեսումը միացված է"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Սարքի կատարողականը նվազեցված է:"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Բացել մարտկոցի տնտեսման կարգավորումները"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3a8aab8..5dbd490 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -243,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Gesek ke kiri untuk kamera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Hingga Anda menonaktifkan ini"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Tamu"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Tamu"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Selama satu menit"</item>
<item quantity="other" msgid="6924190729213550991">"Selama %d menit"</item>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d595089..6ebd5c7 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -245,10 +245,8 @@
<string name="camera_hint" msgid="5241441720959174226">"左にスワイプしてカメラを表示"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"ユーザーがOFFにするまで"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フルになるまで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"ゲスト"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ ゲスト"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1分"</item>
<item quantity="other" msgid="6924190729213550991">"%d分"</item>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 9f7e9bf..8f1f30a 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -32,26 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"შეტყობინებები არ არის."</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"მიმდინარე"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"შეტყობინებები"</string>
- <!-- no translation found for battery_low_title (6456385927409742437) -->
- <skip />
+ <string name="battery_low_title" msgid="6456385927409742437">"ბატარეა იწურება"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"დარჩენილია <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
- <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
- <skip />
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"დარჩენილია <xliff:g id="NUMBER">%d%%</xliff:g>. გააქტიურებულია ბატარეის დამზოგი."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-ით დატენვა არ არის მხარდაჭერილი.\nგამოიყენეთ მხოლოდ ელექტრო-დამტენი."</string>
- <!-- no translation found for invalid_charger_title (3515740382572798460) -->
- <skip />
- <!-- no translation found for invalid_charger_text (5474997287953892710) -->
- <skip />
- <!-- no translation found for battery_low_why (4553600287639198111) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_title (5987726159603849352) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_ok (7283108887345688413) -->
- <skip />
- <!-- no translation found for battery_saver_start_action (7245333922937402896) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_text (8417584516834617662) -->
- <skip />
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB დატენვა მხარდაჭერილი არ არის."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"გამოიყენეთ მხოლოდ მოყოლილი დამტენი."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"პარამეტრები"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"გსურთ ბატარეის დამზოგის დაწყება?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"დაწყება"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"ბატარეის დამზოგის დაწყება"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"ბატარეის მოქმედების გასახანგრძლივებლად, ბატარეის დამზოგი შეამცირებს თქვენი მოწყობილობის წარმადობას.\n\nბატარეის დამზოგი გამოირთვება, როდესაც მოწყობილობას ელკვებაზე მიაერთებთ."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"პარამეტრები"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"თვითმფრინავის რეჟიმი"</string>
@@ -252,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"კამერისთვის მარცხენა შენაცვლება"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"სანამ ამას გამორთავდეთ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"სტუმარი"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ სტუმარი"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"ერთი წუთით"</item>
<item quantity="other" msgid="6924190729213550991">"%d წუთით"</item>
@@ -264,10 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"ერთი საათით"</item>
<item quantity="other" msgid="5408537517529822157">"%d საათით"</item>
</plurals>
- <!-- no translation found for battery_saver_notification_title (237918726750955859) -->
- <skip />
- <!-- no translation found for battery_saver_notification_text (7796554871101546872) -->
- <skip />
- <!-- no translation found for battery_saver_notification_action_text (7546297220816993504) -->
- <skip />
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"ბატარეის დამზოგი ჩართულია"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"მოწყობილობის წარმადობა შემცირებულია."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ბატარეის დამზოგის პარამეტრების გახსნა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index aa4f27d..0ffb4b8 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -245,10 +245,8 @@
<string name="camera_hint" msgid="5241441720959174226">"카메라를 사용하려면 왼쪽으로 스와이프하세요."</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"이 기능을 사용 중지할 때까지"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"손님"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"새 손님 추가"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1분 동안"</item>
<item quantity="other" msgid="6924190729213550991">"%d분 동안"</item>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 5114935..7d8a1ad 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -32,26 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Tiada pemberitahuan"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sedang berlangsung"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
- <!-- no translation found for battery_low_title (6456385927409742437) -->
- <skip />
+ <string name="battery_low_title" msgid="6456385927409742437">"Bateri rendah"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Berbaki <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
- <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
- <skip />
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> yang tinggal. Penjimat bateri dihidupkan."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Pengecasan USB tidak disokong.\nGunakan hanya pengecas yang dibekalkan."</string>
- <!-- no translation found for invalid_charger_title (3515740382572798460) -->
- <skip />
- <!-- no translation found for invalid_charger_text (5474997287953892710) -->
- <skip />
- <!-- no translation found for battery_low_why (4553600287639198111) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_title (5987726159603849352) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_ok (7283108887345688413) -->
- <skip />
- <!-- no translation found for battery_saver_start_action (7245333922937402896) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_text (8417584516834617662) -->
- <skip />
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Pengecasan USB tidak disokong."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Gunakan pengecas yang dibekalkan sahaja."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Tetapan"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Hidupkan penjimat bateri?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Bermula"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Hidupkan penjimat bateri"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Untuk membantu meningkatkan hayat bateri, penjimat Bateri akan mengurangkan prestasi peranti anda.\n\nPenjimat bateri akan dilumpuhkan apabila peranti anda disambungkan kepada sumber kuasa."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Tetapan"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod pesawat"</string>
@@ -232,7 +223,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Sudah dicas"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengecas"</string>
- <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> sehingga penuh"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Lagi <xliff:g id="CHARGING_TIME">%s</xliff:g> untuk penuh"</string>
<string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Tidak mengecas"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rangkaian mungkin\nboleh dipantau"</string>
<string name="description_target_search" msgid="3091587249776033139">"Carian"</string>
@@ -264,10 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Selama satu jam"</item>
<item quantity="other" msgid="5408537517529822157">"Selama %d jam"</item>
</plurals>
- <!-- no translation found for battery_saver_notification_title (237918726750955859) -->
- <skip />
- <!-- no translation found for battery_saver_notification_text (7796554871101546872) -->
- <skip />
- <!-- no translation found for battery_saver_notification_action_text (7546297220816993504) -->
- <skip />
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Penjimat bateri dihidupkan"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Prestasi peranti dikurangkan."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buka tetapan penjimat bateri"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index be9af97..cecbe7a 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -243,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Sveip mot venstre for å åpne kameraet"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Inntil du slår av funksjonen"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Gjest"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Gjest"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"I ett minutt"</item>
<item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 37aae0a..657e03f 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -194,8 +194,8 @@
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brilho"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotação automática"</string>
<string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotação bloqueada"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Vertical"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Horizontal"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Retrato"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Paisagem"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Método de Introdução"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Localização"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localização Desativada"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index a540efbb..bcf7431 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -32,26 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em andamento"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
- <!-- no translation found for battery_low_title (6456385927409742437) -->
- <skip />
+ <string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
- <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
- <skip />
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante(s). A Economia de bateria está ativada."</string>
<string name="invalid_charger" msgid="4549105996740522523">"O carregamento via USB não é suportado.\nUse apenas o carregador fornecido."</string>
- <!-- no translation found for invalid_charger_title (3515740382572798460) -->
- <skip />
- <!-- no translation found for invalid_charger_text (5474997287953892710) -->
- <skip />
- <!-- no translation found for battery_low_why (4553600287639198111) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_title (5987726159603849352) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_ok (7283108887345688413) -->
- <skip />
- <!-- no translation found for battery_saver_start_action (7245333922937402896) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_text (8417584516834617662) -->
- <skip />
+ <string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento via USB não é suportado."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Use apenas o carregador fornecido."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Configurações"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Iniciar a economia de bateria?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar economia de bateria"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ajudar a melhorar a vida útil da bateria, a Economia de bateria reduzirá o desempenho do dispositivo.\n\nA Economia de bateria será desativada quando o dispositivo estiver carregando."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avião"</string>
@@ -254,10 +245,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Deslize para a esquerda para usar a câmera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Até você desativar"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ convidado"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Por 1 minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Por %d minutos"</item>
@@ -266,10 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Por 1 hora"</item>
<item quantity="other" msgid="5408537517529822157">"Por %d horas"</item>
</plurals>
- <!-- no translation found for battery_saver_notification_title (237918726750955859) -->
- <skip />
- <!-- no translation found for battery_saver_notification_text (7796554871101546872) -->
- <skip />
- <!-- no translation found for battery_saver_notification_action_text (7546297220816993504) -->
- <skip />
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"O desempenho do dispositivo foi reduzido."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir configurações de economia de bateria"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e057b76..c099dd9 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -32,26 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nicio notificare"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"În desfăşurare"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificări"</string>
- <!-- no translation found for battery_low_title (6456385927409742437) -->
- <skip />
+ <string name="battery_low_title" msgid="6456385927409742437">"Bateria este aproape descărcată"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Rămas: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
- <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
- <skip />
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Procent rămas din baterie: <xliff:g id="NUMBER">%d%%</xliff:g>. Economisirea bateriei este activată."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. \nUtilizaţi numai încărcătorul furnizat."</string>
- <!-- no translation found for invalid_charger_title (3515740382572798460) -->
- <skip />
- <!-- no translation found for invalid_charger_text (5474997287953892710) -->
- <skip />
- <!-- no translation found for battery_low_why (4553600287639198111) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_title (5987726159603849352) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_ok (7283108887345688413) -->
- <skip />
- <!-- no translation found for battery_saver_start_action (7245333922937402896) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_text (8417584516834617662) -->
- <skip />
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Încărcarea prin USB nu este acceptată."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Utilizați numai încărcătorul furnizat."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Setări"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Porniți economisirea bateriei?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Începeți"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Porniți economisirea bateriei"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Pentru a mări autonomia bateriei, funcția Economisirea bateriei reduce performanța dispozitivului.\n\nEconomisirea bateriei se dezactivează când dispozitivul este conectat la priză."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setări"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod Avion"</string>
@@ -264,10 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Timp de o oră"</item>
<item quantity="other" msgid="5408537517529822157">"Timp de %d (de) ore"</item>
</plurals>
- <!-- no translation found for battery_saver_notification_title (237918726750955859) -->
- <skip />
- <!-- no translation found for battery_saver_notification_text (7796554871101546872) -->
- <skip />
- <!-- no translation found for battery_saver_notification_action_text (7546297220816993504) -->
- <skip />
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Economisirea bateriei este activată"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Performanța dispozitivului s-a redus."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Deschideți setările pentru economisirea bateriei"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 3f95a0c..8c59e05 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -245,10 +245,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Чтобы включить камеру, пролистните влево"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Пока я не отключу"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Гость"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Добавить гостя"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1 мин."</item>
<item quantity="other" msgid="6924190729213550991">"%d мин."</item>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index ad12b18..10ba09f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -243,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Povlecite v levo za fotoaparat"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Dokler tega ne izklopite"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Dodajanje gosta"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Za eno minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Za %d min"</item>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 22a89a9..3bee434 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -243,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Превуците улево за камеру"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Док не искључите"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Гост"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Један минут"</item>
<item quantity="other" msgid="6924190729213550991">"%d мин"</item>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index b49e1a5..42f262b 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -243,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Mag-swipe pakaliwa para sa camera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Hanggang sa i-off mo ito"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Bisita"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Bisita"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Sa loob ng isang minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Sa loob ng %d (na) minuto"</item>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 7bbf9ee..7635c01 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -243,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Kamera için sola kaydırın"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Siz bunu kapatana kadar"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Misafir"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Misafir"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Bir dakika süreyle"</item>
<item quantity="other" msgid="6924190729213550991">"%d dakika süreyle"</item>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 45677f2..e15d3e5 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -243,10 +243,8 @@
<string name="camera_hint" msgid="5241441720959174226">"Vuốt sang trái để mở máy ảnh"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Cho đến khi bạn tắt tính năng này"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"Khách"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Khách"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Trong một phút"</item>
<item quantity="other" msgid="6924190729213550991">"Trong %d phút"</item>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 0d27e29..cfd4fe9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -32,26 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"无通知"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"正在进行的"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <!-- no translation found for battery_low_title (6456385927409742437) -->
- <skip />
+ <string name="battery_low_title" msgid="6456385927409742437">"电池电量偏低"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"还剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
- <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
- <skip />
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"电量还剩<xliff:g id="NUMBER">%d%%</xliff:g>。节电助手已启用。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支持 USB 充电功能。\n只能使用随附的充电器充电。"</string>
- <!-- no translation found for invalid_charger_title (3515740382572798460) -->
- <skip />
- <!-- no translation found for invalid_charger_text (5474997287953892710) -->
- <skip />
- <!-- no translation found for battery_low_why (4553600287639198111) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_title (5987726159603849352) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_ok (7283108887345688413) -->
- <skip />
- <!-- no translation found for battery_saver_start_action (7245333922937402896) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_text (8417584516834617662) -->
- <skip />
+ <string name="invalid_charger_title" msgid="3515740382572798460">"不支持USB充电功能。"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"仅限使用设备随附的充电器。"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"设置"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"启动节电助手?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"启动"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"启动节电助手"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"为了延长电池的续航时间,节电助手会减降设备的性能。\n\n设备接通电源后,节电助手会自动停用。"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"设置"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"飞行模式"</string>
@@ -232,7 +223,7 @@
<string name="recents_empty_message" msgid="7883614615463619450">"最近没有用过任何应用"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
- <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充电"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充电完成"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"正在充电"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"还需<xliff:g id="CHARGING_TIME">%s</xliff:g>才能充满"</string>
<string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"未在充电"</string>
@@ -266,10 +257,7 @@
<item quantity="one" msgid="3480040795582254384">"1小时"</item>
<item quantity="other" msgid="5408537517529822157">"%d小时"</item>
</plurals>
- <!-- no translation found for battery_saver_notification_title (237918726750955859) -->
- <skip />
- <!-- no translation found for battery_saver_notification_text (7796554871101546872) -->
- <skip />
- <!-- no translation found for battery_saver_notification_action_text (7546297220816993504) -->
- <skip />
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"节电助手已启用"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"设备性能已减降。"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"打开节电助手设置"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index c5805a1..4b5cf08 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -42,7 +42,7 @@
<string name="battery_saver_confirmation_title" msgid="5987726159603849352">"啟動節約電池用量模式?"</string>
<string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"開始"</string>
<string name="battery_saver_start_action" msgid="7245333922937402896">"啟動節約電池用量模式"</string>
- <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"節約電池用量模式有助於延長電池壽命,但會讓裝置的效能降低。\n\n裝置接上電源時,節約電池用量模式會自動停用。"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"節約電池用量模式有助於延長電池壽命,但會降低裝置的效能。\n\n裝置接上電源時,節約電池用量模式會自動停用。"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"飛行模式"</string>
@@ -245,10 +245,8 @@
<string name="camera_hint" msgid="5241441720959174226">"向左快速滑動即可使用相機功能"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"直至您關閉這項設定"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
<item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 8f2d247..a780ad1 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -245,10 +245,8 @@
<string name="camera_hint" msgid="5241441720959174226">"向左滑動可使用相機功能"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"手動關閉這項設定前一律啟用"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string>
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (4259024453643879653) -->
- <skip />
+ <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
<item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c8851dc..c64a182 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -111,9 +111,9 @@
<!-- The duration in seconds to wait before the dismiss buttons are shown. -->
<integer name="recents_task_bar_dismiss_delay_seconds">3</integer>
<!-- The min animation duration for animating views that are currently visible. -->
- <integer name="recents_filter_animate_current_views_min_duration">175</integer>
+ <integer name="recents_filter_animate_current_views_duration">250</integer>
<!-- The min animation duration for animating views that are newly visible. -->
- <integer name="recents_filter_animate_new_views_min_duration">125</integer>
+ <integer name="recents_filter_animate_new_views_duration">250</integer>
<!-- The min animation duration for animating the task bar in. -->
<integer name="recents_animate_task_bar_enter_duration">275</integer>
<!-- The animation delay for animating the first task in. This should roughly be the animation
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7ed3e29..bbcc9c1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -212,7 +212,7 @@
<dimen name="glowpadview_inner_radius">15dip</dimen>
<!-- The size of the application icon in the recents task view. -->
- <dimen name="recents_task_view_application_icon_size">32dp</dimen>
+ <dimen name="recents_task_view_application_icon_size">48dp</dimen>
<!-- The size of the activity icon in the recents task view. -->
<dimen name="recents_task_view_activity_icon_size">60dp</dimen>
@@ -330,4 +330,6 @@
phone hints. -->
<dimen name="edge_tap_area_width">48dp</dimen>
+ <!-- end margin for multi user switch in expanded quick settings -->
+ <dimen name="multi_user_switch_expanded_margin">8dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index ffd76a7..b9e2e1ba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -239,6 +239,12 @@
private String mPhoneState = TelephonyManager.EXTRA_STATE_IDLE;
/**
+ * Whether a hide is pending an we are just waiting for #startKeyguardExitAnimation to be
+ * called.
+ * */
+ private boolean mHiding;
+
+ /**
* we send this intent when the keyguard is dismissed.
*/
private static final Intent USER_PRESENT_INTENT = new Intent(Intent.ACTION_USER_PRESENT)
@@ -1169,6 +1175,7 @@
}
mStatusBarKeyguardViewManager.show(options);
+ mHiding = false;
mShowing = true;
mKeyguardDonePending = false;
updateActivityLockScreenState();
@@ -1191,7 +1198,7 @@
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleHide");
try {
-
+ mHiding = true;
if (mShowing) {
// Don't actually hide the Keyguard at the moment, wait for window manager until
@@ -1212,6 +1219,11 @@
private void handleStartKeyguardExitAnimation(long startTime, long fadeoutDuration) {
synchronized (KeyguardViewMediator.this) {
+ if (!mHiding) {
+ return;
+ }
+ mHiding = false;
+
// only play "unlock" noises if not on a call (since the incall UI
// disables the keyguard)
if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index c3ba349c..41b1f75 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -152,6 +152,7 @@
.setContentText(mContext.getString(R.string.invalid_charger_text))
.setPriority(Notification.PRIORITY_MAX)
.setCategory(Notification.CATEGORY_SYSTEM)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
.setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_CHARGER), true);
final Notification n = nb.build();
if (n.headsUpContentView != null) {
@@ -171,6 +172,7 @@
.setOngoing(true)
.setPriority(Notification.PRIORITY_MAX)
.setCategory(Notification.CATEGORY_SYSTEM)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
.setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_WARNING), true);
if (hasBatterySettings()) {
nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
@@ -197,7 +199,8 @@
.setContentText(mContext.getString(R.string.battery_saver_notification_text))
.setOngoing(true)
.setShowWhen(false)
- .setCategory(Notification.CATEGORY_SYSTEM);
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setVisibility(Notification.VISIBILITY_PUBLIC);
if (hasSaverSettings()) {
nb.addAction(0,
mContext.getString(R.string.battery_saver_notification_action_text),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
index b981ed6..c4bdb19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
@@ -69,6 +69,7 @@
@Override
public void onViewAttachedToWindow(View v) {
+ vp.updateStates();
volumeComponent.setVolumePanel(vp);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 1d355cd..ddea0bf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -30,7 +30,7 @@
// Enables the screenshot app->Recents transition
public static final boolean EnableScreenshotAppTransition = false;
// Enables the filtering of tasks according to their grouping
- public static final boolean EnableTaskFiltering = false;
+ public static final boolean EnableTaskFiltering = true;
// Enables clipping of tasks against each other
public static final boolean EnableTaskStackClipping = true;
// Enables the use of theme colors as the task bar background
@@ -48,7 +48,7 @@
// For debugging, this defines the number of mock recents packages to create
public static final int SystemServicesProxyMockPackageCount = 3;
// For debugging, this defines the number of mock recents tasks to create
- public static final int SystemServicesProxyMockTaskCount = 75;
+ public static final int SystemServicesProxyMockTaskCount = 100;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index dce8f57..88ff726 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -72,6 +72,7 @@
FrameLayout mContainerView;
RecentsView mRecentsView;
View mEmptyView;
+ View mStatusBarScrimView;
View mNavBarScrimView;
FullScreenTransitionView mFullScreenshotView;
@@ -180,13 +181,11 @@
AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
mConfig.launchedWithNoRecentTasks = !root.hasTasks();
- if (mConfig.shouldAnimateNavBarScrim()) {
- // Hide the scrim if we animate into Recents with window transitions
- mNavBarScrimView.setVisibility(View.INVISIBLE);
- } else {
- // Show the scrim if we animate into Recents without window transitions
- mNavBarScrimView.setVisibility(View.VISIBLE);
- }
+ // Show the scrim if we animate into Recents without window transitions
+ mNavBarScrimView.setVisibility(mConfig.hasNavBarScrim() &&
+ !mConfig.shouldAnimateNavBarScrim() ? View.VISIBLE : View.INVISIBLE);
+ mStatusBarScrimView.setVisibility(mConfig.hasStatusBarScrim() &&
+ !mConfig.shouldAnimateStatusBarScrim() ? View.VISIBLE : View.INVISIBLE);
// Add the default no-recents layout
if (mConfig.launchedWithNoRecentTasks) {
@@ -325,6 +324,10 @@
// Create the empty view
LayoutInflater inflater = LayoutInflater.from(this);
mEmptyView = inflater.inflate(R.layout.recents_empty, mContainerView, false);
+ mStatusBarScrimView = inflater.inflate(R.layout.recents_status_bar_scrim, mContainerView, false);
+ mStatusBarScrimView.setLayoutParams(new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.TOP));
mNavBarScrimView = inflater.inflate(R.layout.recents_nav_bar_scrim, mContainerView, false);
mNavBarScrimView.setLayoutParams(new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
@@ -336,6 +339,7 @@
}
mContainerView = new FrameLayout(this);
+ mContainerView.addView(mStatusBarScrimView);
mContainerView.addView(mRecentsView);
mContainerView.addView(mEmptyView);
if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
@@ -563,8 +567,18 @@
}
public void onEnterAnimationTriggered() {
- // Fade in the scrim
- if (mConfig.shouldAnimateNavBarScrim() && mConfig.hasNavBarScrim()) {
+ // Fade in the scrims
+ if (mConfig.hasStatusBarScrim() && mConfig.shouldAnimateStatusBarScrim()) {
+ mStatusBarScrimView.setVisibility(View.VISIBLE);
+ mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight());
+ mStatusBarScrimView.animate()
+ .translationY(0)
+ .setStartDelay(mConfig.taskBarEnterAnimDelay)
+ .setDuration(mConfig.navBarScrimEnterDuration)
+ .setInterpolator(mConfig.quintOutInterpolator)
+ .start();
+ }
+ if (mConfig.hasNavBarScrim() && mConfig.shouldAnimateNavBarScrim()) {
mNavBarScrimView.setVisibility(View.VISIBLE);
mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
mNavBarScrimView.animate()
@@ -579,7 +593,7 @@
@Override
public void onExitAnimationTriggered() {
// Fade out the scrim
- if (mConfig.shouldAnimateNavBarScrim() && mConfig.hasNavBarScrim()) {
+ if (mConfig.hasNavBarScrim() && mConfig.shouldAnimateNavBarScrim()) {
mNavBarScrimView.animate()
.translationY(mNavBarScrimView.getMeasuredHeight())
.setStartDelay(0)
@@ -605,14 +619,9 @@
}
@Override
- public void onTaskLaunching(boolean isTaskInStackBounds) {
+ public void onTaskLaunching() {
mTaskLaunched = true;
- // Fade out the scrim
- if (!isTaskInStackBounds && mConfig.hasNavBarScrim()) {
- onExitAnimationTriggered();
- }
-
// Mark recents as no longer visible
AlternateRecentsComponent.notifyVisibilityChanged(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index c1a8ee6..63ef773 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -47,8 +47,8 @@
public Interpolator quintOutInterpolator;
/** Filtering */
- public int filteringCurrentViewsMinAnimDuration;
- public int filteringNewViewsMinAnimDuration;
+ public int filteringCurrentViewsAnimDuration;
+ public int filteringNewViewsAnimDuration;
/** Insets */
public Rect systemInsets = new Rect();
@@ -106,12 +106,30 @@
public boolean developerOptionsEnabled;
/** Private constructor */
- private RecentsConfiguration() {}
+ private RecentsConfiguration(Context context) {
+ // Properties that don't have to be reloaded with each configuration change can be loaded
+ // here.
+
+ // Interpolators
+ fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
+ fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_linear_in);
+ linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.linear_out_slow_in);
+ quintOutInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.decelerate_quint);
+
+ // Check if the developer options are enabled
+ ContentResolver cr = context.getContentResolver();
+ developerOptionsEnabled = Settings.Global.getInt(cr,
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
+ }
/** Updates the configuration to the current context */
public static RecentsConfiguration reinitialize(Context context) {
if (sInstance == null) {
- sInstance = new RecentsConfiguration();
+ sInstance = new RecentsConfiguration(context);
}
sInstance.update(context);
return sInstance;
@@ -132,21 +150,11 @@
animationPxMovementPerSecond =
res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second);
- // Interpolators
- fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
- linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.linear_out_slow_in);
- quintOutInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.decelerate_quint);
-
// Filtering
- filteringCurrentViewsMinAnimDuration =
- res.getInteger(R.integer.recents_filter_animate_current_views_min_duration);
- filteringNewViewsMinAnimDuration =
- res.getInteger(R.integer.recents_filter_animate_new_views_min_duration);
+ filteringCurrentViewsAnimDuration =
+ res.getInteger(R.integer.recents_filter_animate_current_views_duration);
+ filteringNewViewsAnimDuration =
+ res.getInteger(R.integer.recents_filter_animate_new_views_duration);
// Insets
displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
@@ -217,11 +225,6 @@
navBarScrimEnterDuration =
res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
- // Check if the developer options are enabled
- ContentResolver cr = context.getContentResolver();
- developerOptionsEnabled = Settings.Global.getInt(cr,
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
-
if (Console.Enabled) {
Console.log(Constants.Log.UI.MeasureAndLayout,
"[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
@@ -257,6 +260,16 @@
return searchBarAppWidgetId >= 0;
}
+ /** Returns whether the status bar scrim should be animated when shown for the first time. */
+ public boolean shouldAnimateStatusBarScrim() {
+ return launchedFromHome;
+ }
+
+ /** Returns whether the status bar scrim should be visible. */
+ public boolean hasStatusBarScrim() {
+ return !launchedWithNoRecentTasks;
+ }
+
/** Returns whether the nav bar scrim should be animated when shown for the first time. */
public boolean shouldAnimateNavBarScrim() {
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index a02e1a7b..7762111 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -118,6 +118,7 @@
TaskResourceLoadQueue mLoadQueue;
DrawableLruCache mApplicationIconCache;
BitmapLruCache mThumbnailCache;
+ Bitmap mDefaultThumbnail;
boolean mCancelled;
boolean mWaitingOnLoadQueue;
@@ -125,10 +126,12 @@
/** Constructor, creates a new loading thread that loads task resources in the background */
public TaskResourceLoader(TaskResourceLoadQueue loadQueue,
DrawableLruCache applicationIconCache,
- BitmapLruCache thumbnailCache) {
+ BitmapLruCache thumbnailCache,
+ Bitmap defaultThumbnail) {
mLoadQueue = loadQueue;
mApplicationIconCache = applicationIconCache;
mThumbnailCache = thumbnailCache;
+ mDefaultThumbnail = defaultThumbnail;
mMainThreadHandler = new Handler();
mLoadThread = new HandlerThread("Recents-TaskResourceLoader");
mLoadThread.setPriority(Thread.NORM_PRIORITY - 1);
@@ -238,6 +241,7 @@
loadThumbnail = thumbnail;
mThumbnailCache.put(t.key, thumbnail);
} else {
+ loadThumbnail = mDefaultThumbnail;
Console.logError(mContext,
"Failed to load task top thumbnail for: " +
t.key.baseIntent.getComponent().getPackageName());
@@ -330,6 +334,7 @@
BitmapDrawable mDefaultApplicationIcon;
Bitmap mDefaultThumbnail;
+ Bitmap mLoadingThumbnail;
/** Private Constructor */
private RecentsTaskLoader(Context context) {
@@ -356,18 +361,22 @@
mLoadQueue = new TaskResourceLoadQueue();
mApplicationIconCache = new DrawableLruCache(iconCacheSize);
mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
- mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache);
+ mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
+ mDefaultThumbnail);
// Create the default assets
Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
icon.eraseColor(0x00000000);
mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
- mDefaultThumbnail.eraseColor(0x00000000);
+ mDefaultThumbnail.eraseColor(0xFFffffff);
+ mLoadingThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ mLoadingThumbnail.eraseColor(0x00000000);
mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
if (Console.Enabled) {
Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|defaultBitmaps]",
- "icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
+ "icon: " + mDefaultApplicationIcon +
+ " default thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
}
}
@@ -394,7 +403,7 @@
SystemServicesProxy ssp = mSystemServicesProxy;
List<ActivityManager.RecentTaskInfo> tasks =
- ssp.getRecentTasks(100, UserHandle.CURRENT.getIdentifier());
+ ssp.getRecentTasks(50, UserHandle.CURRENT.getIdentifier());
Collections.reverse(tasks);
if (Console.Enabled) {
Console.log(Constants.Log.App.TimeSystemCalls,
@@ -544,7 +553,7 @@
requiresLoad = true;
}
if (thumbnail == null) {
- thumbnail = mDefaultThumbnail;
+ thumbnail = mLoadingThumbnail;
requiresLoad = true;
}
if (requiresLoad) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java b/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
index c861d2c..cadfc56 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
@@ -49,8 +50,8 @@
FullScreenTransitionViewCallbacks mCb;
ImageView mScreenshotView;
-
Rect mClipRect = new Rect();
+ Paint mLayerPaint = new Paint();
boolean mIsAnimating;
AnimatorSet mEnterAnimation;
@@ -159,7 +160,7 @@
int clipBottom = mConfig.systemInsets.top + (int) (ctx.taskRect.height() / scale);
// Enable the HW Layers on the screenshot view
- mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint);
// Compose the animation
mEnterAnimation = new AnimatorSet();
@@ -173,7 +174,7 @@
// Mark that we are no longer animating
mIsAnimating = false;
// Disable the HW Layers on this view
- setLayerType(View.LAYER_TYPE_NONE, null);
+ setLayerType(View.LAYER_TYPE_NONE, mLayerPaint);
if (Console.Enabled) {
Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition,
@@ -217,7 +218,7 @@
// Mark that we are no longer animating
mIsAnimating = false;
// Disable the HW Layers on the screenshot view
- mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint);
}
});
mEnterAnimation.setDuration(475);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 3e6879d..7248758 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -54,7 +54,7 @@
/** The RecentsView callbacks */
public interface RecentsViewCallbacks {
- public void onTaskLaunching(boolean isTaskInStackBounds);
+ public void onTaskLaunching();
public void onExitAnimationTriggered();
}
@@ -389,13 +389,46 @@
final TaskStack stack, final Task task) {
// Notify any callbacks of the launching of a new task
if (mCb != null) {
- boolean isTaskInStackBounds = false;
- if (stackView != null && tv != null) {
- isTaskInStackBounds = stackView.isTaskInStackBounds(tv);
- }
- mCb.onTaskLaunching(isTaskInStackBounds);
+ mCb.onTaskLaunching();
}
+ // Upfront the processing of the thumbnail
+ TaskViewTransform transform;
+ View sourceView = tv;
+ int offsetX = 0;
+ int offsetY = 0;
+ int stackScroll = stackView.getStackScroll();
+ if (tv == null) {
+ // If there is no actual task view, then use the stack view as the source view
+ // and then offset to the expected transform rect, but bound this to just
+ // outside the display rect (to ensure we don't animate from too far away)
+ sourceView = stackView;
+ transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
+ offsetX = transform.rect.left;
+ offsetY = Math.min(transform.rect.top, mConfig.displayRect.height());
+ } else {
+ transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
+ }
+
+ // Compute the thumbnail to scale up from
+ ActivityOptions opts = null;
+ int thumbnailWidth = transform.rect.width();
+ int thumbnailHeight = transform.rect.height();
+ if (task.thumbnail != null && thumbnailWidth > 0 && thumbnailHeight > 0 &&
+ task.thumbnail.getWidth() > 0 && task.thumbnail.getHeight() > 0) {
+ // Resize the thumbnail to the size of the view that we are animating from
+ Bitmap b = Bitmap.createBitmap(thumbnailWidth, thumbnailHeight,
+ Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ c.drawBitmap(task.thumbnail,
+ new Rect(0, 0, task.thumbnail.getWidth(), task.thumbnail.getHeight()),
+ new Rect(0, 0, thumbnailWidth, thumbnailHeight), null);
+ c.setBitmap(null);
+ opts = ActivityOptions.makeThumbnailScaleUpAnimation(sourceView,
+ b, offsetX, offsetY);
+ }
+
+ final ActivityOptions launchOpts = opts;
final Runnable launchRunnable = new Runnable() {
@Override
public void run() {
@@ -404,45 +437,10 @@
Constants.Log.App.TimeRecentsLaunchKey, "preStartActivity");
}
- TaskViewTransform transform;
- View sourceView = tv;
- int offsetX = 0;
- int offsetY = 0;
- int stackScroll = stackView.getStackScroll();
- if (tv == null) {
- // If there is no actual task view, then use the stack view as the source view
- // and then offset to the expected transform rect, but bound this to just
- // outside the display rect (to ensure we don't animate from too far away)
- sourceView = stackView;
- transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
- offsetX = transform.rect.left;
- offsetY = Math.min(transform.rect.top, mConfig.displayRect.height());
- } else {
- transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
- }
-
- // Compute the thumbnail to scale up from
- ActivityOptions opts = null;
- int thumbnailWidth = transform.rect.width();
- int thumbnailHeight = transform.rect.height();
- if (task.thumbnail != null && thumbnailWidth > 0 && thumbnailHeight > 0 &&
- task.thumbnail.getWidth() > 0 && task.thumbnail.getHeight() > 0) {
- // Resize the thumbnail to the size of the view that we are animating from
- Bitmap b = Bitmap.createBitmap(thumbnailWidth, thumbnailHeight,
- Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(b);
- c.drawBitmap(task.thumbnail,
- new Rect(0, 0, task.thumbnail.getWidth(), task.thumbnail.getHeight()),
- new Rect(0, 0, thumbnailWidth, thumbnailHeight), null);
- c.setBitmap(null);
- opts = ActivityOptions.makeThumbnailScaleUpAnimation(sourceView,
- b, offsetX, offsetY);
- }
-
if (task.isActive) {
// Bring an active task to the foreground
RecentsTaskLoader.getInstance().getSystemServicesProxy()
- .moveTaskToFront(task.key.id, opts);
+ .moveTaskToFront(task.key.id, launchOpts);
} else {
// Launch the activity anew with the desired animation
Intent i = new Intent(task.key.baseIntent);
@@ -451,8 +449,8 @@
| Intent.FLAG_ACTIVITY_NEW_TASK);
try {
UserHandle taskUser = new UserHandle(task.userId);
- if (opts != null) {
- getContext().startActivityAsUser(i, opts.toBundle(), taskUser);
+ if (launchOpts != null) {
+ getContext().startActivityAsUser(i, launchOpts.toBundle(), taskUser);
} else {
getContext().startActivityAsUser(i, taskUser);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index 82d6220..bf25760 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -23,6 +23,7 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewPropertyAnimator;
@@ -50,6 +51,7 @@
Drawable mLightDismissDrawable;
Drawable mDarkDismissDrawable;
+ Paint mLayerPaint = new Paint();
static Paint sHighlightPaint;
public TaskBarView(Context context) {
@@ -91,6 +93,13 @@
mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
mActivityDescription = (TextView) findViewById(R.id.activity_description);
mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
+
+ // Hide the backgrounds if they are ripple drawables
+ if (!Constants.DebugFlags.App.EnableTaskFiltering) {
+ if (mApplicationIcon.getBackground() instanceof RippleDrawable) {
+ mApplicationIcon.setBackground(null);
+ }
+ }
}
@Override
@@ -237,11 +246,11 @@
/** Enable the hw layers on this task view */
void enableHwLayers() {
- mDismissButton.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mDismissButton.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint);
}
/** Disable the hw layers on this task view */
void disableHwLayers() {
- mDismissButton.setLayerType(View.LAYER_TYPE_NONE, null);
+ mDismissButton.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index e0a12b7..6c12218 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -187,12 +187,20 @@
return null;
}
- /** Update/get the transform */
+ /** Update/get the transform (creates a new TaskViewTransform) */
public TaskViewTransform getStackTransform(int indexInStack, int stackScroll) {
TaskViewTransform transform = new TaskViewTransform();
+ return getStackTransform(indexInStack, stackScroll, transform);
+ }
+ /** Update/get the transform */
+ public TaskViewTransform getStackTransform(int indexInStack, int stackScroll,
+ TaskViewTransform transformOut) {
// Return early if we have an invalid index
- if (indexInStack < 0) return transform;
+ if (indexInStack < 0) {
+ transformOut.reset();
+ return transformOut;
+ }
// Map the items to an continuous position relative to the specified scroll
int numPeekCards = Constants.Values.TaskStackView.StackPeekNumCards;
@@ -209,35 +217,35 @@
float scale = Math.max(minScale, Math.min(1f, minScale +
((boundedT + (numPeekCards + 1)) * scaleInc)));
float scaleYOffset = ((1f - scale) * mTaskRect.height()) / 2;
- transform.scale = scale;
+ transformOut.scale = scale;
// Set the y translation
if (boundedT < 0f) {
- transform.translationY = (int) ((Math.max(-numPeekCards, boundedT) /
+ transformOut.translationY = (int) ((Math.max(-numPeekCards, boundedT) /
numPeekCards) * peekHeight - scaleYOffset);
} else {
- transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
+ transformOut.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
}
// Set the z translation
int minZ = mConfig.taskViewTranslationZMinPx;
int incZ = mConfig.taskViewTranslationZIncrementPx;
- transform.translationZ = (int) Math.max(minZ, minZ + ((boundedT + numPeekCards) * incZ));
+ transformOut.translationZ = (int) Math.max(minZ, minZ + ((boundedT + numPeekCards) * incZ));
// Set the alphas
- transform.dismissAlpha = Math.max(-1f, Math.min(0f, t + 1)) + 1f;
+ transformOut.dismissAlpha = Math.max(-1f, Math.min(0f, t + 1)) + 1f;
// Update the rect and visibility
- transform.rect.set(mTaskRect);
+ transformOut.rect.set(mTaskRect);
if (t < -(numPeekCards + 1)) {
- transform.visible = false;
+ transformOut.visible = false;
} else {
- transform.rect.offset(0, transform.translationY);
- Utilities.scaleRectAboutCenter(transform.rect, transform.scale);
- transform.visible = Rect.intersects(mRect, transform.rect);
+ transformOut.rect.offset(0, transformOut.translationY);
+ Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
+ transformOut.visible = Rect.intersects(mRect, transformOut.rect);
}
- transform.t = t;
- return transform;
+ transformOut.t = t;
+ return transformOut;
}
/**
@@ -250,14 +258,25 @@
boolean boundTranslationsToRect) {
// XXX: Optimization: Use binary search to find the visible range
+ int taskTransformCount = taskTransforms.size();
int taskCount = tasks.size();
int firstVisibleIndex = -1;
int lastVisibleIndex = -1;
- taskTransforms.clear();
- taskTransforms.ensureCapacity(taskCount);
+
+ // We can reuse the task transforms where possible to reduce object allocation
+ if (taskTransformCount < taskCount) {
+ // If there are less transforms than tasks, then add as many transforms as necessary
+ for (int i = taskTransformCount; i < taskCount; i++) {
+ taskTransforms.add(new TaskViewTransform());
+ }
+ } else if (taskTransformCount > taskCount) {
+ // If there are more transforms than tasks, then just subset the transform list
+ taskTransforms.subList(0, taskCount);
+ }
+
+ // Update the stack transforms
for (int i = 0; i < taskCount; i++) {
- TaskViewTransform transform = getStackTransform(i, stackScroll);
- taskTransforms.add(transform);
+ TaskViewTransform transform = getStackTransform(i, stackScroll, taskTransforms.get(i));
if (transform.visible) {
if (firstVisibleIndex < 0) {
firstVisibleIndex = i;
@@ -958,6 +977,7 @@
ArrayList<TaskView> childrenToRemoveOut) {
// Animate all of the existing views out of view (if they are not in the visible range in
// the new stack) or to their final positions in the new stack
+ int offset = 0;
int movement = 0;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -982,10 +1002,13 @@
movement = Math.max(movement, Math.abs(toTransform.translationY -
(int) tv.getTranslationY()));
}
- childViewTransformsOut.put(tv, new Pair(0, toTransform));
+
+ int startDelay = offset *
+ Constants.Values.TaskStackView.FilterStartDelay;
+ childViewTransformsOut.put(tv, new Pair(startDelay, toTransform));
+ offset++;
}
- return Utilities.calculateTranslationAnimationDuration(movement,
- mConfig.filteringCurrentViewsMinAnimDuration);
+ return mConfig.filteringCurrentViewsAnimDuration;
}
/**
@@ -1023,8 +1046,7 @@
}
}
}
- return Utilities.calculateTranslationAnimationDuration(movement,
- mConfig.filteringNewViewsMinAnimDuration);
+ return mConfig.filteringNewViewsAnimDuration;
}
/** Orchestrates the animations of the current child views and any new views. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 09dc1c8..0b19162 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Outline;
+import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
@@ -63,6 +64,7 @@
Point mLastTouchDown = new Point();
Path mRoundedRectClipPath = new Path();
Rect mTmpRect = new Rect();
+ Paint mLayerPaint = new Paint();
TaskThumbnailView mThumbnailView;
TaskBarView mBarView;
@@ -440,13 +442,13 @@
/** Enable the hw layers on this task view */
void enableHwLayers() {
- mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint);
mBarView.enableHwLayers();
}
/** Disable the hw layers on this task view */
void disableHwLayers() {
- mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint);
mBarView.disableHwLayers();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 6c420e1..1947e30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -28,7 +28,7 @@
public float dismissAlpha = 1f;
public boolean visible = false;
public Rect rect = new Rect();
- float t;
+ float t = 0f;
public TaskViewTransform() {
// Do nothing
@@ -45,6 +45,18 @@
t = o.t;
}
+ /** Resets the current transform */
+ public void reset() {
+ translationY = 0;
+ translationZ = 0;
+ scale = 1f;
+ alpha = 1f;
+ dismissAlpha = 1f;
+ visible = false;
+ rect.setEmpty();
+ t = 0f;
+ }
+
/** Convenience functions to compare against current property values */
public boolean hasAlphaChangedFrom(float v) {
return (Float.compare(alpha, v) != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 20684a1..5bc23b5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -311,8 +311,27 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- if (mNotificationData.findByKey(sbn.getKey()) != null ||
- isHeadsUp(sbn.getKey())) {
+ Notification n = sbn.getNotification();
+ boolean isUpdate = mNotificationData.findByKey(sbn.getKey()) != null
+ || isHeadsUp(sbn.getKey());
+ boolean isGroupedChild = n.getGroup() != null
+ && (n.flags & Notification.FLAG_GROUP_SUMMARY) == 0;
+ if (isGroupedChild) {
+ if (DEBUG) {
+ Log.d(TAG, "Ignoring group child: " + sbn);
+ }
+ // Don't show grouped notifications. If this is an
+ // update, i.e. the notification existed before but
+ // wasn't a group child, remove the old instance.
+ // Otherwise just update the ranking.
+ if (isUpdate) {
+ removeNotificationInternal(sbn.getKey(), rankingMap);
+ } else {
+ updateRankingInternal(rankingMap);
+ }
+ return;
+ }
+ if (isUpdate) {
updateNotificationInternal(sbn, rankingMap);
} else {
addNotificationInternal(sbn, rankingMap);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index c8ab027..1712124 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -70,6 +70,8 @@
private int mKeyguardWidth = ViewGroup.LayoutParams.MATCH_PARENT;
private int mNormalWidth;
+ private int mPadding;
+ private int mMultiUserExpandedMargin;
private ActivityStarter mActivityStarter;
private BrightnessController mBrightnessController;
@@ -120,6 +122,10 @@
mKeyguardHeight = getResources().getDimensionPixelSize(
R.dimen.status_bar_header_height_keyguard);
mNormalWidth = getLayoutParams().width;
+ mPadding = getResources().getDimensionPixelSize(R.dimen.notification_side_padding);
+ mMultiUserExpandedMargin =
+ getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin);
+
}
public void setActivityStarter(ActivityStarter activityStarter) {
@@ -147,6 +153,8 @@
updateZTranslation();
updateClickTargets();
updateWidth();
+ updatePadding();
+ updateMultiUserSwitch();
if (mQSPanel != null) {
mQSPanel.setExpanded(expanded && !overscrolled);
}
@@ -256,6 +264,21 @@
}
}
+ private void updatePadding() {
+ boolean padded = !mKeyguardShowing || mExpanded;
+ int padding = padded ? mPadding : 0;
+ setPaddingRelative(padding, 0, padding, 0);
+ }
+
+ private void updateMultiUserSwitch() {
+ int marginEnd = !mKeyguardShowing || mExpanded ? mMultiUserExpandedMargin : 0;
+ MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams();
+ if (marginEnd != lp.getMarginEnd()) {
+ lp.setMarginEnd(marginEnd);
+ mMultiUserSwitch.setLayoutParams(lp);
+ }
+ }
+
public void setExpansion(float height) {
height = (height - mCollapsedHeight) * EXPANSION_RUBBERBAND_FACTOR + mCollapsedHeight;
if (height < mCollapsedHeight) {
@@ -301,6 +324,8 @@
updateWidth();
updateVisibilities();
updateZTranslation();
+ updatePadding();
+ updateMultiUserSwitch();
}
public void setUserInfoController(UserInfoController userInfoController) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 4cbb06b..ccbaed3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -969,7 +969,7 @@
* @param animate Should an animation be performed.
*/
public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
- setOverScrollAmount(numPixels * getRubberBandFactor(), onTop, animate, true);
+ setOverScrollAmount(numPixels * getRubberBandFactor(onTop), onTop, animate, true);
}
/**
@@ -1005,7 +1005,7 @@
if (animate) {
mStateAnimator.animateOverScrollToAmount(amount, onTop);
} else {
- setOverScrolledPixels(amount / getRubberBandFactor(), onTop);
+ setOverScrolledPixels(amount / getRubberBandFactor(onTop), onTop);
mAmbientState.setOverScrollAmount(amount, onTop);
if (onTop) {
notifyOverscrollTopListener(amount);
@@ -1227,13 +1227,14 @@
mOwnScrollY -= (int) topAmount;
mDontReportNextOverScroll = true;
setOverScrollAmount(0, true, false);
- mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor()
+ mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */)
* mOverflingDistance + topAmount;
} else if (velocityY > 0 && bottomAmount > 0) {
mOwnScrollY += bottomAmount;
setOverScrollAmount(0, false, false);
- mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor()
- * mOverflingDistance + bottomAmount;
+ mMaxOverScroll = Math.abs(velocityY) / 1000f
+ * getRubberBandFactor(false /* onTop */) * mOverflingDistance
+ + bottomAmount;
} else {
// it will be set once we reach the boundary
mMaxOverScroll = 0.0f;
@@ -1275,7 +1276,10 @@
return Math.max(desiredPadding, mIntrinsicPadding);
}
- private float getRubberBandFactor() {
+ private float getRubberBandFactor(boolean onTop) {
+ if (!onTop) {
+ return RUBBER_BAND_FACTOR_NORMAL;
+ }
if (mExpandedInThisMotion) {
return RUBBER_BAND_FACTOR_AFTER_EXPAND;
} else if (mIsExpansionChanging) {
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index b22aeb7..4318b9d 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -111,10 +111,10 @@
FontFamily serifFamily = new FontFamily();
serifFamily.mNames = sSerifNames;
- serifFamily.mNormalFileName = "DroidSerif-Regular.ttf";
- serifFamily.mBoldFileName = "DroidSerif-Bold.ttf";
- serifFamily.mItalicFileName = "DroidSerif-Italic.ttf";
- serifFamily.mBoldItalicFileName = "DroidSerif-BoldItalic.ttf";
+ serifFamily.mNormalFileName = "NotoSerif-Regular.ttf";
+ serifFamily.mBoldFileName = "NotoSerif-Bold.ttf";
+ serifFamily.mItalicFileName = "NotoSerif-Italic.ttf";
+ serifFamily.mBoldItalicFileName = "NotoSerif-BoldItalic.ttf";
addFamilyToMap(serifFamily);
FontFamily monoFamily = new FontFamily();
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index cef6830..3b1e88a 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -28,6 +28,7 @@
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupTransport;
import android.app.backup.FullBackup;
+import android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
import android.app.backup.IBackupManager;
import android.app.backup.IFullBackupRestoreObserver;
@@ -5177,7 +5178,9 @@
void restorePmMetadata() {
try {
- String packageName = mTransport.nextRestorePackage();
+ RestoreDescription desc = mTransport.nextRestorePackage();
+ // TODO: handle full-data stream restore payloads
+ String packageName = desc.getPackageName();
if (packageName == null) {
Slog.e(TAG, "Error getting first restore package");
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
@@ -5245,7 +5248,9 @@
void restoreNextAgent() {
try {
- String packageName = mTransport.nextRestorePackage();
+ final RestoreDescription desc = mTransport.nextRestorePackage();
+ // TODO: handle full-data stream restore payloads
+ String packageName = desc.getPackageName();
if (packageName == null) {
Slog.e(TAG, "Error getting next restore package");
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index aeb195f..912a181 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -18,6 +18,7 @@
import android.database.ContentObserver;
import android.os.BatteryStats;
+
import com.android.internal.app.IBatteryStats;
import com.android.server.am.BatteryStatsService;
import com.android.server.lights.Light;
@@ -29,6 +30,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
import android.os.BatteryProperties;
import android.os.Binder;
import android.os.FileUtils;
@@ -83,7 +85,7 @@
* service asynchronously itself.
* </p>
*/
-public final class BatteryService extends Binder {
+public final class BatteryService extends SystemService {
private static final String TAG = BatteryService.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -140,10 +142,12 @@
private boolean mSentLowBatteryBroadcast = false;
- public BatteryService(Context context, LightsManager lightsManager) {
+ public BatteryService(Context context) {
+ super(context);
+
mContext = context;
mHandler = new Handler(true /*async*/);
- mLed = new Led(context, lightsManager);
+ mLed = new Led(context, getLocalService(LightsManager.class));
mBatteryStats = BatteryStatsService.getService();
mCriticalBatteryLevel = mContext.getResources().getInteger(
@@ -160,7 +164,10 @@
mInvalidChargerObserver.startObserving(
"DEVPATH=/devices/virtual/switch/invalid_charger");
}
+ }
+ @Override
+ public void onStart() {
IBinder b = ServiceManager.getService("batteryproperties");
final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
IBatteryPropertiesRegistrar.Stub.asInterface(b);
@@ -169,28 +176,34 @@
} catch (RemoteException e) {
// Should never happen.
}
+
+ publishBinderService("battery", new BinderService());
+ publishLocalService(BatteryManagerInternal.class, new LocalService());
}
- void systemReady() {
- // check our power situation now that it is safe to display the shutdown dialog.
- synchronized (mLock) {
- ContentObserver obs = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- synchronized (mLock) {
- updateBatteryWarningLevelLocked();
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_ACTIVITY_MANAGER_READY) {
+ // check our power situation now that it is safe to display the shutdown dialog.
+ synchronized (mLock) {
+ ContentObserver obs = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ synchronized (mLock) {
+ updateBatteryWarningLevelLocked();
+ }
}
- }
- };
- final ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
- false, obs, UserHandle.USER_ALL);
- updateBatteryWarningLevelLocked();
+ };
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+ false, obs, UserHandle.USER_ALL);
+ updateBatteryWarningLevelLocked();
+ }
}
}
- void updateBatteryWarningLevelLocked() {
+ private void updateBatteryWarningLevelLocked() {
final ContentResolver resolver = mContext.getContentResolver();
int defWarnLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
@@ -207,15 +220,6 @@
processValuesLocked(true);
}
- /**
- * Returns true if the device is plugged into any of the specified plug types.
- */
- public boolean isPowered(int plugTypeSet) {
- synchronized (mLock) {
- return isPoweredLocked(plugTypeSet);
- }
- }
-
private boolean isPoweredLocked(int plugTypeSet) {
// assume we are powered if battery state is unknown so
// the "stay on while plugged in" option will work.
@@ -234,34 +238,7 @@
return false;
}
- /**
- * Returns the current plug type.
- */
- public int getPlugType() {
- synchronized (mLock) {
- return mPlugType;
- }
- }
-
- /**
- * Returns battery level as a percentage.
- */
- public int getBatteryLevel() {
- synchronized (mLock) {
- return mBatteryProps.batteryLevel;
- }
- }
-
- /**
- * Returns whether we currently consider the battery level to be low.
- */
- public boolean getBatteryLevelLow() {
- synchronized (mLock) {
- return mBatteryLevelLow;
- }
- }
-
- public boolean shouldSendBatteryLowLocked() {
+ private boolean shouldSendBatteryLowLocked() {
final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
@@ -277,15 +254,6 @@
&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
}
- /**
- * Returns a non-zero value if an unsupported charger is attached.
- */
- public int getInvalidCharger() {
- synchronized (mLock) {
- return mInvalidCharger;
- }
- }
-
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
@@ -640,17 +608,7 @@
}
}
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
-
- pw.println("Permission Denial: can't dump Battery service from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
+ private void dumpInternal(PrintWriter pw, String[] args) {
synchronized (mLock) {
if (args == null || args.length == 0 || "-a".equals(args[0])) {
pw.println("Current Battery Service state:");
@@ -801,4 +759,57 @@
}
}
}
+
+ private final class BinderService extends Binder {
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ pw.println("Permission Denial: can't dump Battery service from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ dumpInternal(pw, args);
+ }
+ }
+
+ private final class LocalService extends BatteryManagerInternal {
+ @Override
+ public boolean isPowered(int plugTypeSet) {
+ synchronized (mLock) {
+ return isPoweredLocked(plugTypeSet);
+ }
+ }
+
+ @Override
+ public int getPlugType() {
+ synchronized (mLock) {
+ return mPlugType;
+ }
+ }
+
+ @Override
+ public int getBatteryLevel() {
+ synchronized (mLock) {
+ return mBatteryProps.batteryLevel;
+ }
+ }
+
+ @Override
+ public boolean getBatteryLevelLow() {
+ synchronized (mLock) {
+ return mBatteryLevelLow;
+ }
+ }
+
+ @Override
+ public int getInvalidCharger() {
+ synchronized (mLock) {
+ return mInvalidCharger;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/IdleMaintenanceService.java b/services/core/java/com/android/server/IdleMaintenanceService.java
deleted file mode 100644
index acc6abe..0000000
--- a/services/core/java/com/android/server/IdleMaintenanceService.java
+++ /dev/null
@@ -1,818 +0,0 @@
-/*
- * 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.server;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.maintenance.IIdleCallback;
-import android.app.maintenance.IIdleService;
-import android.app.maintenance.IdleService;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.WorkSource;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * This service observes the device state and when applicable sends
- * broadcasts at the beginning and at the end of a period during which
- * observers can perform idle maintenance tasks. Typical use of the
- * idle maintenance is to perform somehow expensive tasks that can be
- * postponed to a moment when they will not degrade user experience.
- *
- * The current implementation is very simple. The start of a maintenance
- * window is announced if: the screen is off or showing a dream AND the
- * battery level is more than twenty percent AND at least one hour passed
- * activity).
- *
- * The end of a maintenance window is announced only if: a start was
- * announced AND the screen turned on or a dream was stopped.
- *
- * Method naming note:
- * Methods whose name ends with "Tm" must only be called from the main thread.
- */
-public class IdleMaintenanceService extends BroadcastReceiver {
-
- private static final boolean DEBUG = false;
-
- private static final String TAG = IdleMaintenanceService.class.getSimpleName();
-
- private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1;
-
- private static final long MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS = 24 * 60 * 60 * 1000; // 1 day
-
- private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING = 30; // percent
-
- private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING = 80; // percent
-
- private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING = 20; // percent
-
- private static final long MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START = 71 * 60 * 1000; // 71 min
-
- private static final long MAX_IDLE_MAINTENANCE_DURATION = 71 * 60 * 1000; // 71 min
-
- private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE =
- "com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE";
-
- private static final String ACTION_FORCE_IDLE_MAINTENANCE =
- "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE";
-
- static final int MSG_OP_COMPLETE = 1;
- static final int MSG_IDLE_FINISHED = 2;
- static final int MSG_TIMEOUT = 3;
-
- // when a timeout happened, what were we expecting?
- static final int VERB_BINDING = 1;
- static final int VERB_IDLING = 2;
- static final int VERB_ENDING = 3;
-
- // What are our relevant timeouts / allocated slices?
- static final long OP_TIMEOUT = 8 * 1000; // 8 seconds to bind or ack the start
- static final long IDLE_TIMESLICE = 10 * 60 * 1000; // ten minutes for each idler
-
- private final AlarmManager mAlarmService;
- private final BatteryService mBatteryService;
- private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent;
- private final Context mContext;
- private final WakeLock mWakeLock;
- private final WorkSource mSystemWorkSource = new WorkSource(Process.myUid());
-
- private long mLastIdleMaintenanceStartTimeMillis;
- private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
- private boolean mIdleMaintenanceStarted;
-
- final IdleCallback mCallback;
- final Handler mHandler;
-
- final Random mTokenGenerator = new Random();
-
- int makeToken() {
- int token;
- do {
- token = mTokenGenerator.nextInt(Integer.MAX_VALUE);
- } while (token == 0);
- return token;
- }
-
- class ActiveTask {
- public IdleServiceInfo who;
- public int verb;
- public int token;
-
- ActiveTask(IdleServiceInfo target, int action) {
- who = target;
- verb = action;
- token = makeToken();
- }
-
- @Override
- public String toString() {
- return "ActiveTask{" + Integer.toHexString(this.hashCode())
- + " : verb=" + verb
- + " : token=" + token
- + " : "+ who + "}";
- }
- }
-
- // What operations are in flight?
- final SparseArray<ActiveTask> mPendingOperations = new SparseArray<ActiveTask>();
-
- // Idle service queue management
- class IdleServiceInfo {
- public final ComponentName componentName;
- public final int uid;
- public IIdleService service;
-
- IdleServiceInfo(ResolveInfo info, ComponentName cname) {
- componentName = cname; // derived from 'info' but this avoids an extra object
- uid = info.serviceInfo.applicationInfo.uid;
- service = null;
- }
-
- @Override
- public int hashCode() {
- return componentName.hashCode();
- }
-
- @Override
- public String toString() {
- return "IdleServiceInfo{" + componentName
- + " / " + (service == null ? "null" : service.asBinder()) + "}";
- }
- }
-
- final ArrayMap<ComponentName, IdleServiceInfo> mIdleServices =
- new ArrayMap<ComponentName, IdleServiceInfo>();
- final LinkedList<IdleServiceInfo> mIdleServiceQueue = new LinkedList<IdleServiceInfo>();
- IdleServiceInfo mCurrentIdler; // set when we've committed to launching an idler
- IdleServiceInfo mLastIdler; // end of queue when idling begins
-
- void reportNoTimeout(int token, boolean result) {
- final Message msg = mHandler.obtainMessage(MSG_OP_COMPLETE, result ? 1 : 0, token);
- mHandler.sendMessage(msg);
- }
-
- // Binder acknowledgment trampoline
- class IdleCallback extends IIdleCallback.Stub {
- @Override
- public void acknowledgeStart(int token, boolean result) throws RemoteException {
- reportNoTimeout(token, result);
- }
-
- @Override
- public void acknowledgeStop(int token) throws RemoteException {
- reportNoTimeout(token, false);
- }
-
- @Override
- public void idleFinished(int token) throws RemoteException {
- if (DEBUG) {
- Slog.v(TAG, "idleFinished: " + token);
- }
- final Message msg = mHandler.obtainMessage(MSG_IDLE_FINISHED, 0, token);
- mHandler.sendMessage(msg);
- }
- }
-
- // Stuff that we run on a Handler
- class IdleHandler extends Handler {
- public IdleHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- final int token = msg.arg2;
-
- switch (msg.what) {
- case MSG_OP_COMPLETE: {
- if (DEBUG) {
- Slog.i(TAG, "MSG_OP_COMPLETE of " + token);
- }
- ActiveTask task = mPendingOperations.get(token);
- if (task != null) {
- mPendingOperations.remove(token);
- removeMessages(MSG_TIMEOUT);
-
- handleOpCompleteTm(task, msg.arg1);
- } else {
- // Can happen in a race between timeout and actual
- // (belated) completion of a "begin idling" or similar
- // operation. In that state we've already processed the
- // timeout, so we intentionally no-op here.
- if (DEBUG) {
- Slog.w(TAG, "Belated op-complete of " + token);
- }
- }
- break;
- }
-
- case MSG_IDLE_FINISHED: {
- if (DEBUG) {
- Slog.i(TAG, "MSG_IDLE_FINISHED of " + token);
- }
- ActiveTask task = mPendingOperations.get(token);
- if (task != null) {
- if (DEBUG) {
- Slog.i(TAG, "... removing task " + token);
- }
- mPendingOperations.remove(token);
- removeMessages(MSG_TIMEOUT);
-
- handleIdleFinishedTm(task);
- } else {
- // Can happen "legitimately" from an app explicitly calling
- // idleFinished() after already having been told that its slice
- // has ended.
- if (DEBUG) {
- Slog.w(TAG, "Belated idle-finished of " + token);
- }
- }
- break;
- }
-
- case MSG_TIMEOUT: {
- if (DEBUG) {
- Slog.i(TAG, "MSG_TIMEOUT of " + token);
- }
- ActiveTask task = mPendingOperations.get(token);
- if (task != null) {
- mPendingOperations.remove(token);
- removeMessages(MSG_OP_COMPLETE);
-
- handleTimeoutTm(task);
- } else {
- // This one should not happen; we flushed timeout messages
- // whenever we entered a state after which we have established
- // that they are not appropriate.
- Slog.w(TAG, "Unexpected timeout of " + token);
- }
- break;
- }
-
- default:
- Slog.w(TAG, "Unknown message: " + msg.what);
- }
- }
- }
-
- void handleTimeoutTm(ActiveTask task) {
- switch (task.verb) {
- case VERB_BINDING: {
- // We were trying to bind to this service, but it wedged or otherwise
- // failed to respond in time. Let it stay in the queue for the next
- // time around, but just give up on it for now and go on to the next.
- startNextIdleServiceTm();
- break;
- }
- case VERB_IDLING: {
- // The service has reached the end of its designated idle timeslice.
- // This is not considered an error.
- if (DEBUG) {
- Slog.i(TAG, "Idler reached end of timeslice: " + task.who);
- }
- sendEndIdleTm(task.who);
- break;
- }
- case VERB_ENDING: {
- if (mCurrentIdler == task.who) {
- if (DEBUG) {
- Slog.i(TAG, "Task timed out when ending; unbind needed");
- }
- handleIdleFinishedTm(task);
- } else {
- if (DEBUG) {
- Slog.w(TAG, "Ending timeout for non-current idle service!");
- }
- }
- break;
- }
- default: {
- Slog.w(TAG, "Unknown timeout state " + task.verb);
- break;
- }
- }
- }
-
- void handleOpCompleteTm(ActiveTask task, int result) {
- if (DEBUG) {
- Slog.i(TAG, "handleOpComplete : task=" + task + " result=" + result);
- }
- if (task.verb == VERB_IDLING) {
- // If the service was told to begin idling and responded positively, then
- // it has begun idling and will eventually either explicitly finish, or
- // reach the end of its allotted timeslice. It's running free now, so we
- // just schedule the idle-expiration timeout under the token it's already been
- // given and let it keep going.
- if (result != 0) {
- scheduleOpTimeoutTm(task);
- } else {
- // The idle service has indicated that it does not, in fact,
- // need to run at present, so we immediately indicate that it's
- // to finish idling, and go on to the next idler.
- if (DEBUG) {
- Slog.i(TAG, "Idler declined idling; moving along");
- }
- sendEndIdleTm(task.who);
- }
- } else {
- // In the idling case, the task will be cleared either as the result of a timeout
- // or of an explicit idleFinished(). For all other operations (binding, ending) we
- // are done with the task as such, so we remove it from our bookkeeping.
- if (DEBUG) {
- Slog.i(TAG, "Clearing task " + task);
- }
- mPendingOperations.remove(task.token);
- if (task.verb == VERB_ENDING) {
- // The last bit of handshaking around idle cessation for this target
- handleIdleFinishedTm(task);
- }
- }
- }
-
- void handleIdleFinishedTm(ActiveTask task) {
- final IdleServiceInfo who = task.who;
- if (who == mCurrentIdler) {
- if (DEBUG) {
- Slog.i(TAG, "Current idler has finished: " + who);
- Slog.i(TAG, "Attributing wakelock to system work source");
- }
- mContext.unbindService(mConnection);
- startNextIdleServiceTm();
- } else {
- Slog.w(TAG, "finish from non-current idle service? " + who);
- }
- }
-
- void updateIdleServiceQueueTm() {
- if (DEBUG) {
- Slog.i(TAG, "Updating idle service queue");
- }
- PackageManager pm = mContext.getPackageManager();
- Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
- List<ResolveInfo> services = pm.queryIntentServices(idleIntent, 0);
- for (ResolveInfo info : services) {
- if (info.serviceInfo != null) {
- if (IdleService.PERMISSION_BIND.equals(info.serviceInfo.permission)) {
- final ComponentName componentName = new ComponentName(
- info.serviceInfo.packageName,
- info.serviceInfo.name);
- if (DEBUG) {
- Slog.i(TAG, " - " + componentName);
- }
- if (!mIdleServices.containsKey(componentName)) {
- if (DEBUG) {
- Slog.i(TAG, " + not known; adding");
- }
- IdleServiceInfo serviceInfo = new IdleServiceInfo(info, componentName);
- mIdleServices.put(componentName, serviceInfo);
- mIdleServiceQueue.add(serviceInfo);
- }
- } else {
- if (DEBUG) {
- Slog.i(TAG, "Idle service " + info.serviceInfo
- + " does not have required permission; ignoring");
- }
- }
- }
- }
- }
-
- void startNextIdleServiceTm() {
- mWakeLock.setWorkSource(mSystemWorkSource);
-
- if (mLastIdler == null) {
- // we've run the queue; nothing more to do until the next idle interval.
- if (DEBUG) {
- Slog.i(TAG, "Queue already drained; nothing more to do");
- }
- return;
- }
-
- if (DEBUG) {
- Slog.i(TAG, "startNextIdleService : last=" + mLastIdler + " cur=" + mCurrentIdler);
- if (mIdleServiceQueue.size() > 0) {
- int i = 0;
- Slog.i(TAG, "Queue (" + mIdleServiceQueue.size() + "):");
- for (IdleServiceInfo info : mIdleServiceQueue) {
- Slog.i(TAG, " " + i + " : " + info);
- i++;
- }
- }
- }
- if (mCurrentIdler != mLastIdler) {
- if (mIdleServiceQueue.size() > 0) {
- IdleServiceInfo target = mIdleServiceQueue.pop();
- if (DEBUG) {
- Slog.i(TAG, "starting next idle service " + target);
- }
- Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
- idleIntent.setComponent(target.componentName);
- mCurrentIdler = target;
- ActiveTask task = new ActiveTask(target, VERB_BINDING);
- scheduleOpTimeoutTm(task);
- boolean bindOk = mContext.bindServiceAsUser(idleIntent, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY, UserHandle.OWNER);
- if (!bindOk) {
- if (DEBUG) {
- Slog.w(TAG, "bindService() to " + target.componentName
- + " failed");
- }
- } else {
- mIdleServiceQueue.add(target); // at the end for next time
- if (DEBUG) { Slog.i(TAG, "Attributing wakelock to target uid " + target.uid); }
- mWakeLock.setWorkSource(new WorkSource(target.uid));
- }
- } else {
- // Queue is empty but mLastIdler is non-null -- eeep. Clear *everything*
- // and wind up until the next time around.
- Slog.e(TAG, "Queue unexpectedly empty; resetting. last="
- + mLastIdler + " cur=" + mCurrentIdler);
- mHandler.removeMessages(MSG_TIMEOUT);
- mPendingOperations.clear();
- stopIdleMaintenanceTm();
- }
- } else {
- // we've reached the place we started, so mark the queue as drained
- if (DEBUG) {
- Slog.i(TAG, "Reached end of queue.");
- }
- stopIdleMaintenanceTm();
- }
- }
-
- void sendStartIdleTm(IdleServiceInfo who) {
- ActiveTask task = new ActiveTask(who, VERB_IDLING);
- scheduleOpTimeoutTm(task);
- try {
- who.service.startIdleMaintenance(mCallback, task.token);
- } catch (RemoteException e) {
- // We bound to it, but now we can't reach it. Bail and go on to the
- // next service.
- mContext.unbindService(mConnection);
- if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
- mHandler.removeMessages(MSG_TIMEOUT);
- startNextIdleServiceTm();
- }
- }
-
- void sendEndIdleTm(IdleServiceInfo who) {
- ActiveTask task = new ActiveTask(who, VERB_ENDING);
- scheduleOpTimeoutTm(task);
- if (DEBUG) {
- Slog.i(TAG, "Sending end-idle to " + who);
- }
- try {
- who.service.stopIdleMaintenance(mCallback, task.token);
- } catch (RemoteException e) {
- // We bound to it, but now we can't reach it. Bail and go on to the
- // next service.
- mContext.unbindService(mConnection);
- if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
- mHandler.removeMessages(MSG_TIMEOUT);
- startNextIdleServiceTm();
- }
- }
-
- ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) {
- Slog.i(TAG, "onServiceConnected(" + name + ")");
- }
- IdleServiceInfo info = mIdleServices.get(name);
- if (info != null) {
- // Bound! Cancel the bind timeout
- mHandler.removeMessages(MSG_TIMEOUT);
- // Now tell it to start its idle work
- info.service = IIdleService.Stub.asInterface(service);
- sendStartIdleTm(info);
- } else {
- // We bound to a service we don't know about. That's ungood.
- Slog.e(TAG, "Connected to unexpected component " + name);
- mContext.unbindService(this);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) {
- Slog.i(TAG, "onServiceDisconnected(" + name + ")");
- }
- IdleServiceInfo who = mIdleServices.get(name);
- if (who == mCurrentIdler) {
- // Hm, okay; they didn't tell us they were finished but they
- // went away. Crashed, probably. Oh well. They're gone, so
- // we can't finish them cleanly; just force things along.
- Slog.w(TAG, "Idler unexpectedly vanished: " + mCurrentIdler);
- mContext.unbindService(this);
- mHandler.removeMessages(MSG_TIMEOUT);
- startNextIdleServiceTm();
- } else {
- // Not the current idler, so we don't interrupt our process...
- if (DEBUG) {
- Slog.w(TAG, "Disconnect of abandoned or unexpected service " + name);
- }
- }
- }
- };
-
- // Schedules a timeout / end-of-work based on the task verb
- void scheduleOpTimeoutTm(ActiveTask task) {
- final long timeoutMillis = (task.verb == VERB_IDLING) ? IDLE_TIMESLICE : OP_TIMEOUT;
- if (DEBUG) {
- Slog.i(TAG, "Scheduling timeout (token " + task.token
- + " : verb " + task.verb + ") for " + task + " in " + timeoutMillis);
- }
- mPendingOperations.put(task.token, task);
- mHandler.removeMessages(MSG_TIMEOUT);
- final Message msg = mHandler.obtainMessage(MSG_TIMEOUT, 0, task.token);
- mHandler.sendMessageDelayed(msg, timeoutMillis);
- }
-
- // -------------------------------------------------------------------------------
- public IdleMaintenanceService(Context context, BatteryService batteryService) {
- mContext = context;
- mBatteryService = batteryService;
-
- mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-
- PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
- mHandler = new IdleHandler(mContext.getMainLooper());
- mCallback = new IdleCallback();
-
- Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
- intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0,
- intent, PendingIntent.FLAG_UPDATE_CURRENT);
-
- register(mHandler);
- }
-
- public void register(Handler handler) {
- IntentFilter intentFilter = new IntentFilter();
-
- // Alarm actions.
- intentFilter.addAction(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
-
- // Battery actions.
- intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
-
- // Screen actions.
- intentFilter.addAction(Intent.ACTION_SCREEN_ON);
- intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
-
- // Dream actions.
- intentFilter.addAction(Intent.ACTION_DREAMING_STARTED);
- intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
-
- mContext.registerReceiverAsUser(this, UserHandle.ALL,
- intentFilter, null, mHandler);
-
- intentFilter = new IntentFilter();
- intentFilter.addAction(ACTION_FORCE_IDLE_MAINTENANCE);
- mContext.registerReceiverAsUser(this, UserHandle.ALL,
- intentFilter, android.Manifest.permission.SET_ACTIVITY_WATCHER, mHandler);
- }
-
- private void scheduleUpdateIdleMaintenanceState(long delayMillis) {
- final long triggetRealTimeMillis = SystemClock.elapsedRealtime() + delayMillis;
- mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggetRealTimeMillis,
- mUpdateIdleMaintenanceStatePendingIntent);
- }
-
- private void unscheduleUpdateIdleMaintenanceState() {
- mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
- }
-
- private void updateIdleMaintenanceStateTm(boolean noisy) {
- if (mIdleMaintenanceStarted) {
- // Idle maintenance can be interrupted by user activity, or duration
- // time out, or low battery.
- final boolean batteryOk
- = batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning();
- if (!lastUserActivityPermitsIdleMaintenanceRunning() || !batteryOk) {
- unscheduleUpdateIdleMaintenanceState();
- mIdleMaintenanceStarted = false;
- // We stopped since we don't have enough battery or timed out but the
- // user is not using the device, so we should be able to run maintenance
- // in the next maintenance window since the battery may be charged
- // without interaction and the min interval between maintenances passed.
- if (!batteryOk) {
- scheduleUpdateIdleMaintenanceState(
- getNextIdleMaintenanceIntervalStartFromNow());
- }
-
- EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(),
- mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
- isBatteryCharging() ? 1 : 0);
- scheduleIdleFinishTm();
- }
- } else if (deviceStatePermitsIdleMaintenanceStart(noisy)
- && lastUserActivityPermitsIdleMaintenanceStart(noisy)
- && lastRunPermitsIdleMaintenanceStart(noisy)) {
- // Now that we started idle maintenance, we should schedule another
- // update for the moment when the idle maintenance times out.
- scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION);
- mIdleMaintenanceStarted = true;
- EventLogTags.writeIdleMaintenanceWindowStart(SystemClock.elapsedRealtime(),
- mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
- isBatteryCharging() ? 1 : 0);
- mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
- startIdleMaintenanceTm();
- } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) {
- if (lastRunPermitsIdleMaintenanceStart(noisy)) {
- // The user does not use the device and we did not run maintenance in more
- // than the min interval between runs, so schedule an update - maybe the
- // battery will be charged latter.
- scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
- } else {
- // The user does not use the device but we have run maintenance in the min
- // interval between runs, so schedule an update after the min interval ends.
- scheduleUpdateIdleMaintenanceState(
- getNextIdleMaintenanceIntervalStartFromNow());
- }
- }
- }
-
- void startIdleMaintenanceTm() {
- if (DEBUG) {
- Slog.i(TAG, "*** Starting idle maintenance ***");
- }
- if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
- mWakeLock.setWorkSource(mSystemWorkSource);
- mWakeLock.acquire();
- updateIdleServiceQueueTm();
- mCurrentIdler = null;
- mLastIdler = (mIdleServiceQueue.size() > 0) ? mIdleServiceQueue.peekLast() : null;
- startNextIdleServiceTm();
- }
-
- // Start a graceful wind-down of the idle maintenance state: end the current idler
- // and pretend that we've finished running the queue. If there's no current idler,
- // this is a no-op.
- void scheduleIdleFinishTm() {
- if (mCurrentIdler != null) {
- if (DEBUG) {
- Slog.i(TAG, "*** Finishing idle maintenance ***");
- }
- mLastIdler = mCurrentIdler;
- sendEndIdleTm(mCurrentIdler);
- } else {
- if (DEBUG) {
- Slog.w(TAG, "Asked to finish idle maintenance but we're done already");
- }
- }
- }
-
- // Actual finalization of the idle maintenance sequence
- void stopIdleMaintenanceTm() {
- if (mLastIdler != null) {
- if (DEBUG) {
- Slog.i(TAG, "*** Idle maintenance shutdown ***");
- }
- mWakeLock.setWorkSource(mSystemWorkSource);
- mLastIdler = mCurrentIdler = null;
- updateIdleMaintenanceStateTm(false); // resets 'started' and schedules next window
- mWakeLock.release();
- } else {
- Slog.e(TAG, "ERROR: idle shutdown but invariants not held. last=" + mLastIdler
- + " cur=" + mCurrentIdler + " size=" + mIdleServiceQueue.size());
- }
- }
-
- private long getNextIdleMaintenanceIntervalStartFromNow() {
- return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS
- - SystemClock.elapsedRealtime();
- }
-
- private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) {
- final int minBatteryLevel = isBatteryCharging()
- ? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
- : MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING;
- boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
- && mBatteryService.getBatteryLevel() > minBatteryLevel);
- if (!allowed && noisy) {
- Slog.i("IdleMaintenance", "Idle maintenance not allowed due to power");
- }
- return allowed;
- }
-
- private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) {
- // The last time the user poked the device is above the threshold.
- boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
- && SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis
- > MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
- if (!allowed && noisy) {
- Slog.i("IdleMaintenance", "Idle maintenance not allowed due to last user activity");
- }
- return allowed;
- }
-
- private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) {
- // Enough time passed since the last maintenance run.
- boolean allowed = SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
- > MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
- if (!allowed && noisy) {
- Slog.i("IdleMaintenance", "Idle maintenance not allowed due time since last");
- }
- return allowed;
- }
-
- private boolean lastUserActivityPermitsIdleMaintenanceRunning() {
- // The user is not using the device.
- return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID);
- }
-
- private boolean batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning() {
- // Battery not too low and the maintenance duration did not timeout.
- return (mBatteryService.getBatteryLevel() > MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING
- && mLastIdleMaintenanceStartTimeMillis + MAX_IDLE_MAINTENANCE_DURATION
- > SystemClock.elapsedRealtime());
- }
-
- private boolean isBatteryCharging() {
- return mBatteryService.getPlugType() > 0
- && mBatteryService.getInvalidCharger() == 0;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Log.i(TAG, intent.getAction());
- }
- String action = intent.getAction();
- if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
- // We care about battery only if maintenance is in progress so we can
- // stop it if battery is too low. Note that here we assume that the
- // maintenance clients are properly holding a wake lock. We will
- // refactor the maintenance to use services instead of intents for the
- // next release. The only client for this for now is internal an holds
- // a wake lock correctly.
- if (mIdleMaintenanceStarted) {
- updateIdleMaintenanceStateTm(false);
- }
- } else if (Intent.ACTION_SCREEN_ON.equals(action)
- || Intent.ACTION_DREAMING_STOPPED.equals(action)) {
- mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
- // Unschedule any future updates since we already know that maintenance
- // cannot be performed since the user is back.
- unscheduleUpdateIdleMaintenanceState();
- // If the screen went on/stopped dreaming, we know the user is using the
- // device which means that idle maintenance should be stopped if running.
- updateIdleMaintenanceStateTm(false);
- } else if (Intent.ACTION_SCREEN_OFF.equals(action)
- || Intent.ACTION_DREAMING_STARTED.equals(action)) {
- mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
- // If screen went off/started dreaming, we may be able to start idle maintenance
- // after the minimal user inactivity elapses. We schedule an alarm for when
- // this timeout elapses since the device may go to sleep by then.
- scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
- } else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) {
- updateIdleMaintenanceStateTm(false);
- } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) {
- long now = SystemClock.elapsedRealtime() - 1;
- mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START;
- mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
- updateIdleMaintenanceStateTm(true);
- }
- }
-}
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index bcb6e9e..215d92d 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -30,8 +30,7 @@
private static final String TAG = "MountServiceIdler";
private static ComponentName sIdleService =
- new ComponentName(MountServiceIdler.class.getPackage().getName(),
- MountServiceIdler.class.getName());
+ new ComponentName("android", MountServiceIdler.class.getName());
private static int MOUNT_JOB_ID = 808;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 697e1f2..34c1ecd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2194,6 +2194,11 @@
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
}
+ public void initPowerManagement() {
+ mStackSupervisor.initPowerManagement();
+ mBatteryStatsService.initPowerManagement();
+ }
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -7625,14 +7630,24 @@
}
}
- private boolean isLockTaskAuthorized(ComponentName name) {
+ private boolean isLockTaskAuthorized(String pkg) {
final DevicePolicyManager dpm = (DevicePolicyManager)
mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- return dpm != null && dpm.isLockTaskPermitted(name);
+ try {
+ int uid = mContext.getPackageManager().getPackageUid(pkg,
+ Binder.getCallingUserHandle().getIdentifier());
+ return (uid == Binder.getCallingUid()) && dpm != null && dpm.isLockTaskPermitted(pkg);
+ } catch (NameNotFoundException e) {
+ return false;
+ }
}
private void startLockTaskMode(TaskRecord task) {
- if (!isLockTaskAuthorized(task.intent.getComponent())) {
+ final String pkg;
+ synchronized (this) {
+ pkg = task.intent.getComponent().getPackageName();
+ }
+ if (!isLockTaskAuthorized(pkg)) {
return;
}
long ident = Binder.clearCallingIdentity();
@@ -7641,6 +7656,9 @@
// Since we lost lock on task, make sure it is still there.
task = mStackSupervisor.anyTaskForIdLocked(task.taskId);
if (task != null) {
+ if ((mFocusedActivity == null) || (task != mFocusedActivity.task)) {
+ throw new IllegalArgumentException("Invalid task, not in foreground");
+ }
mStackSupervisor.setLockTaskModeLocked(task);
}
}
@@ -7651,25 +7669,25 @@
@Override
public void startLockTaskMode(int taskId) {
+ final TaskRecord task;
long ident = Binder.clearCallingIdentity();
try {
- final TaskRecord task;
synchronized (this) {
task = mStackSupervisor.anyTaskForIdLocked(taskId);
}
- if (task != null) {
- startLockTaskMode(task);
- }
} finally {
Binder.restoreCallingIdentity(ident);
}
+ if (task != null) {
+ startLockTaskMode(task);
+ }
}
@Override
public void startLockTaskMode(IBinder token) {
+ final TaskRecord task;
long ident = Binder.clearCallingIdentity();
try {
- final TaskRecord task;
synchronized (this) {
final ActivityRecord r = ActivityRecord.forToken(token);
if (r == null) {
@@ -7677,24 +7695,27 @@
}
task = r.task;
}
- if (task != null) {
- startLockTaskMode(task);
- }
} finally {
Binder.restoreCallingIdentity(ident);
}
+ if (task != null) {
+ startLockTaskMode(task);
+ }
}
@Override
public void stopLockTaskMode() {
- // Check if the calling task is eligible to use lock task
- final int uid = Binder.getCallingUid();
+ // Verify that the user matches the package of the intent for the TaskRecord
+ // we are locked to. This will ensure the same caller for startLockTaskMode and
+ // stopLockTaskMode.
try {
- final String name = AppGlobals.getPackageManager().getNameForUid(uid);
- if (!isLockTaskAuthorized(new ComponentName(name, name))) {
- return;
+ String pkg = mStackSupervisor.mLockTaskModeTask.intent.getPackage();
+ int uid = mContext.getPackageManager().getPackageUid(pkg,
+ Binder.getCallingUserHandle().getIdentifier());
+ if (uid != Binder.getCallingUid()) {
+ throw new SecurityException("Invalid uid, expected " + uid);
}
- } catch (RemoteException e) {
+ } catch (NameNotFoundException e) {
Log.d(TAG, "stopLockTaskMode " + e);
return;
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 11f855e..dd9cae9 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager.TaskDescription;
import android.os.PersistableBundle;
import android.os.Trace;
+
import com.android.internal.app.ResolverActivity;
import com.android.internal.util.XmlUtils;
import com.android.server.AttributeCache;
@@ -49,6 +50,7 @@
import android.util.TimeUtils;
import android.view.IApplicationToken;
import android.view.WindowManager;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -58,6 +60,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Objects;
/**
* An entry in the history stack, representing an activity.
@@ -83,6 +86,7 @@
final ActivityManagerService service; // owner
final IApplicationToken.Stub appToken; // window manager token
final ActivityInfo info; // all about me
+ final ApplicationInfo appInfo; // information about activity's app
final int launchedFromUid; // always the uid who started the activity.
final String launchedFromPackage; // always the package who started the activity.
final int userId; // Which user is this running for?
@@ -103,9 +107,6 @@
static final int RECENTS_ACTIVITY_TYPE = 2;
int mActivityType;
- final String baseDir; // where activity source (resources etc) located
- final String resDir; // where public activity source (public resources etc) located
- final String dataDir; // where activity data should go
CharSequence nonLocalizedLabel; // the label information from the package mgr.
int labelRes; // the label information from the package mgr.
int icon; // resource identifier of activity's icon.
@@ -184,11 +185,13 @@
pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
pw.print(prefix); pw.print("realActivity=");
pw.println(realActivity.flattenToShortString());
- pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
- if (!resDir.equals(baseDir)) {
- pw.print(prefix); pw.print("resDir="); pw.println(resDir);
+ if (appInfo != null) {
+ pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir);
+ if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
+ pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
+ }
+ pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
}
- pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
pw.print(" componentSpecified="); pw.print(componentSpecified);
pw.print(" mActivityType="); pw.println(mActivityType);
@@ -418,9 +421,7 @@
taskAffinity = aInfo.taskAffinity;
stateNotNeeded = (aInfo.flags&
ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0;
- baseDir = aInfo.applicationInfo.sourceDir;
- resDir = aInfo.applicationInfo.publicSourceDir;
- dataDir = aInfo.applicationInfo.dataDir;
+ appInfo = aInfo.applicationInfo;
nonLocalizedLabel = aInfo.nonLocalizedLabel;
labelRes = aInfo.labelRes;
if (nonLocalizedLabel == null && labelRes == 0) {
@@ -488,9 +489,7 @@
realActivity = null;
taskAffinity = null;
stateNotNeeded = false;
- baseDir = null;
- resDir = null;
- dataDir = null;
+ appInfo = null;
processName = null;
packageName = null;
fullscreen = true;
@@ -568,7 +567,10 @@
}
boolean isPersistable() {
- return (info.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
+ return (info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY ||
+ info.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS) &&
+ (intent == null ||
+ (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
}
void makeFinishing() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 66e9eb3e..9b1d0e3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -227,14 +227,14 @@
* receivers to launch an activity and get that to run before the device
* goes back to sleep.
*/
- final PowerManager.WakeLock mLaunchingActivity;
+ PowerManager.WakeLock mLaunchingActivity;
/**
* Set when the system is going to sleep, until we have
* successfully paused the current activity and released our wake lock.
* At that point the system is allowed to actually sleep.
*/
- final PowerManager.WakeLock mGoingToSleep;
+ PowerManager.WakeLock mGoingToSleep;
/** Stack id of the front stack when user switched, indexed by userId. */
SparseIntArray mUserStackInFront = new SparseIntArray(2);
@@ -251,16 +251,20 @@
/** If non-null then the task specified remains in front and no other tasks may be started
* until the task exits or #stopLockTaskMode() is called. */
- private TaskRecord mLockTaskModeTask;
+ TaskRecord mLockTaskModeTask;
public ActivityStackSupervisor(ActivityManagerService service) {
mService = service;
+ mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
+ }
+
+ /**
+ * At the time when the constructor runs, the power manager has not yet been
+ * initialized. So we initialize our wakelocks afterwards.
+ */
+ void initPowerManagement() {
PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
- mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
- if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
- throw new IllegalStateException("Calling must be system uid");
- }
mLaunchingActivity =
pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
mLaunchingActivity.setReferenceCounted(false);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index eb253eb..f403d08 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -74,12 +74,19 @@
mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout)
* 1000L);
+ }
+
+ /**
+ * At the time when the constructor runs, the power manager has not yet been
+ * initialized. So we initialize the low power observer later.
+ */
+ public void initPowerManagement() {
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mPowerManagerInternal.registerLowPowerModeObserver(this);
mStats.noteLowPowerMode(mPowerManagerInternal.getLowPowerModeEnabled());
(new WakeupReasonThread()).start();
- }
-
+ }
+
public void shutdown() {
Slog.w("BatteryStats", "Writing battery stats before shutdown...");
synchronized (mStats) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index e54c95e..f79c026 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -45,6 +45,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* A running application service.
@@ -70,9 +71,6 @@
final String packageName; // the package implementing intent's component
final String processName; // process where this component wants to run
final String permission;// permission needed to access service
- final String baseDir; // where activity source (resources etc) located
- final String resDir; // where public activity source (public resources etc) located
- final String dataDir; // where activity data should go
final boolean exported; // from ServiceInfo.exported
final Runnable restarter; // used to schedule retries of starting the service
final long createTime; // when this service was created
@@ -209,11 +207,13 @@
}
long now = SystemClock.uptimeMillis();
long nowReal = SystemClock.elapsedRealtime();
- pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
- if (!resDir.equals(baseDir)) {
- pw.print(prefix); pw.print("resDir="); pw.println(resDir);
+ if (appInfo != null) {
+ pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir);
+ if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
+ pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
+ }
+ pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
}
- pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
pw.print(prefix); pw.print("app="); pw.println(app);
if (isolatedProc != null) {
pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
@@ -305,9 +305,6 @@
packageName = sInfo.applicationInfo.packageName;
processName = sInfo.processName;
permission = sInfo.permission;
- baseDir = sInfo.applicationInfo.sourceDir;
- resDir = sInfo.applicationInfo.publicSourceDir;
- dataDir = sInfo.applicationInfo.dataDir;
exported = sInfo.exported;
this.restarter = restarter;
createTime = SystemClock.elapsedRealtime();
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index bb289fa..c79b33d 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -45,7 +45,7 @@
static final boolean DEBUG = false;
/** When in slow mode don't write tasks out faster than this */
- private static final long INTER_TASK_DELAY_MS = 60000;
+ private static final long INTER_TASK_DELAY_MS = 10000;
private static final long DEBUG_INTER_TASK_DELAY_MS = 5000;
private static final String RECENTS_FILENAME = "_task";
@@ -69,6 +69,7 @@
TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor) {
sTasksDir = new File(systemDir, TASKS_DIRNAME);
if (!sTasksDir.exists()) {
+ if (DEBUG) Slog.d(TAG, "Creating tasks directory " + sTasksDir);
if (!sTasksDir.mkdir()) {
Slog.e(TAG, "Failure creating tasks directory " + sTasksDir);
}
@@ -76,6 +77,7 @@
sImagesDir = new File(systemDir, IMAGES_DIRNAME);
if (!sImagesDir.exists()) {
+ if (DEBUG) Slog.d(TAG, "Creating images directory " + sTasksDir);
if (!sImagesDir.mkdir()) {
Slog.e(TAG, "Failure creating images directory " + sImagesDir);
}
@@ -172,14 +174,15 @@
TaskRecord.restoreFromXml(in, mStackSupervisor);
if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" + task);
if (task != null) {
+ task.isPersistable = true;
tasks.add(task);
final int taskId = task.taskId;
recoveredTaskIds.add(taskId);
mStackSupervisor.setNextTaskId(taskId);
}
} else {
- Slog.e(TAG, "restoreTasksLocked Unknown xml event=" + event + " name="
- + name);
+ Slog.wtf(TAG, "restoreTasksLocked Unknown xml event=" + event +
+ " name=" + name);
}
}
XmlUtils.skipCurrentTag(in);
@@ -195,6 +198,7 @@
}
}
if (!DEBUG && deleteFile) {
+ if (DEBUG) Slog.d(TAG, "Deleting file=" + taskFile.getName());
taskFile.delete();
}
}
@@ -209,7 +213,7 @@
Arrays.sort(tasksArray, new Comparator<TaskRecord>() {
@Override
public int compare(TaskRecord lhs, TaskRecord rhs) {
- final long diff = lhs.mLastTimeMoved - rhs.mLastTimeMoved;
+ final long diff = rhs.mLastTimeMoved - lhs.mLastTimeMoved;
if (diff < 0) {
return -1;
} else if (diff > 0) {
@@ -233,8 +237,7 @@
try {
taskId = Integer.valueOf(filename.substring(0, taskIdEnd));
} catch (Exception e) {
- if (DEBUG) Slog.d(TAG, "removeObsoleteFile: Can't parse file=" +
- file.getName());
+ Slog.wtf(TAG, "removeObsoleteFile: Can't parse file=" + file.getName());
file.delete();
continue;
}
@@ -288,15 +291,18 @@
synchronized(mService) {
final ArrayList<TaskRecord> tasks = mService.mRecentTasks;
persistentTaskIds.clear();
+ if (DEBUG) Slog.d(TAG, "mRecents=" + tasks);
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
task = tasks.get(taskNdx);
if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" +
task.isPersistable + " needsPersisting=" + task.needsPersisting);
- if (task.isPersistable) {
+ if (task.isPersistable && !task.stack.isHomeStack()) {
+ if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
persistentTaskIds.add(task.taskId);
if (task.needsPersisting) {
try {
+ if (DEBUG) Slog.d(TAG, "Saving task=" + task);
stringWriter = saveToXml(task);
break;
} catch (IOException e) {
@@ -305,6 +311,8 @@
task.needsPersisting = false;
}
}
+ } else {
+ if (DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" + task);
}
}
}
@@ -330,6 +338,8 @@
// Made it through the entire list and didn't find anything new that needed
// persisting.
if (!DEBUG) {
+ if (DEBUG) Slog.d(TAG, "Calling removeObsoleteFiles persistentTaskIds=" +
+ persistentTaskIds);
removeObsoleteFiles(persistentTaskIds);
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 81a0b36..1cde41f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -652,8 +652,9 @@
final int numActivities = activities.size();
for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
- if (!r.isPersistable() || (activityNdx > 0 &&
- (r.intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0)) {
+ if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
+ ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) &&
+ activityNdx > 0) {
// Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
break;
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index a77443d..c7f4f6a 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -119,7 +119,7 @@
public int height;
/**
- * The refresh rate of the display.
+ * The refresh rate of the display, in frames per second.
*/
public float refreshRate;
@@ -144,6 +144,20 @@
public float yDpi;
/**
+ * This is a positive value indicating the phase offset of the VSYNC events provided by
+ * Choreographer relative to the display refresh. For example, if Choreographer reports
+ * that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos).
+ */
+ public long appVsyncOffsetNanos;
+
+ /**
+ * This is how far in advance a buffer must be queued for presentation at
+ * a given time. If you want a buffer to appear on the screen at
+ * time N, you must submit the buffer before (N - bufferDeadlineNanos).
+ */
+ public long presentationDeadlineNanos;
+
+ /**
* Display flags.
*/
public int flags;
@@ -219,6 +233,8 @@
&& densityDpi == other.densityDpi
&& xDpi == other.xDpi
&& yDpi == other.yDpi
+ && appVsyncOffsetNanos == other.appVsyncOffsetNanos
+ && presentationDeadlineNanos == other.presentationDeadlineNanos
&& flags == other.flags
&& touch == other.touch
&& rotation == other.rotation
@@ -242,6 +258,8 @@
densityDpi = other.densityDpi;
xDpi = other.xDpi;
yDpi = other.yDpi;
+ appVsyncOffsetNanos = other.appVsyncOffsetNanos;
+ presentationDeadlineNanos = other.presentationDeadlineNanos;
flags = other.flags;
touch = other.touch;
rotation = other.rotation;
@@ -261,6 +279,8 @@
sb.append(", ").append(refreshRate).append(" fps, ");
sb.append("density ").append(densityDpi);
sb.append(", ").append(xDpi).append(" x ").append(yDpi).append(" dpi");
+ sb.append(", appVsyncOff ").append(appVsyncOffsetNanos);
+ sb.append(", presDeadline ").append(presentationDeadlineNanos);
sb.append(", touch ").append(touchToString(touch));
sb.append(", rotation ").append(rotation);
sb.append(", type ").append(Display.typeToString(type));
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index e80aecd..098537c 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -161,6 +161,8 @@
mInfo.width = mPhys.width;
mInfo.height = mPhys.height;
mInfo.refreshRate = mPhys.refreshRate;
+ mInfo.appVsyncOffsetNanos = mPhys.appVsyncOffsetNanos;
+ mInfo.presentationDeadlineNanos = mPhys.presentationDeadlineNanos;
mInfo.state = mState;
// Assume that all built-in displays that have secure output (eg. HDCP) also
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index d61a35b..ed619d9 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -213,6 +213,8 @@
mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
+ mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos;
+ mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos;
mBaseDisplayInfo.state = deviceInfo.state;
mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index bfd8372c..3b23b6a 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -191,6 +191,7 @@
private final int mWidth;
private final int mHeight;
private final float mRefreshRate;
+ private final long mDisplayPresentationDeadlineNanos;
private final int mDensityDpi;
private final boolean mSecure;
@@ -200,7 +201,7 @@
private DisplayDeviceInfo mInfo;
public OverlayDisplayDevice(IBinder displayToken, String name,
- int width, int height, float refreshRate,
+ int width, int height, float refreshRate, long presentationDeadlineNanos,
int densityDpi, boolean secure, int state,
SurfaceTexture surfaceTexture) {
super(OverlayDisplayAdapter.this, displayToken);
@@ -208,6 +209,7 @@
mWidth = width;
mHeight = height;
mRefreshRate = refreshRate;
+ mDisplayPresentationDeadlineNanos = presentationDeadlineNanos;
mDensityDpi = densityDpi;
mSecure = secure;
mState = state;
@@ -249,6 +251,8 @@
mInfo.densityDpi = mDensityDpi;
mInfo.xDpi = mDensityDpi;
mInfo.yDpi = mDensityDpi;
+ mInfo.presentationDeadlineNanos = mDisplayPresentationDeadlineNanos +
+ 1000000000L / (int) mRefreshRate; // display's deadline + 1 frame
mInfo.flags = DisplayDeviceInfo.FLAG_PRESENTATION;
if (mSecure) {
mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
@@ -297,12 +301,13 @@
// Called on the UI thread.
@Override
- public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate, int state) {
+ public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate,
+ long presentationDeadlineNanos, int state) {
synchronized (getSyncRoot()) {
IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);
mDevice = new OverlayDisplayDevice(displayToken, mName,
- mWidth, mHeight, refreshRate, mDensityDpi, mSecure,
- state, surfaceTexture);
+ mWidth, mHeight, refreshRate, presentationDeadlineNanos,
+ mDensityDpi, mSecure, state, surfaceTexture);
sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
}
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index 06891f3..9ca5fda 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -303,7 +303,7 @@
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
int width, int height) {
mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate,
- mDefaultDisplayInfo.state);
+ mDefaultDisplayInfo.presentationDeadlineNanos, mDefaultDisplayInfo.state);
}
@Override
@@ -373,7 +373,7 @@
*/
public interface Listener {
public void onWindowCreated(SurfaceTexture surfaceTexture,
- float refreshRate, int state);
+ float refreshRate, long presentationDeadlineNanos, int state);
public void onWindowDestroyed();
public void onStateChanged(int state);
}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 14ef5a9..ec14cf1 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -171,6 +171,7 @@
mInfo.densityDpi = mDensityDpi;
mInfo.xDpi = mDensityDpi;
mInfo.yDpi = mDensityDpi;
+ mInfo.presentationDeadlineNanos = 1000000000L / (int) mInfo.refreshRate; // 1 frame
mInfo.flags = 0;
if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index cd57941..a05bf2c 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -127,7 +127,7 @@
pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
pw.println("mPendingNotificationUpdate=" + mPendingNotificationUpdate);
pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
-
+
// Try to dump the controller state.
if (mDisplayController == null) {
pw.println("mDisplayController=null");
@@ -729,6 +729,7 @@
mInfo.width = mWidth;
mInfo.height = mHeight;
mInfo.refreshRate = mRefreshRate;
+ mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame
mInfo.flags = mFlags;
mInfo.type = Display.TYPE_WIFI;
mInfo.address = mAddress;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
new file mode 100644
index 0000000..2941574
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -0,0 +1,328 @@
+/**
+ * Copyright (C) 2014 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.server.fingerprint;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.service.fingerprint.FingerprintManager;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.IFingerprintService;
+import android.service.fingerprint.IFingerprintServiceReceiver;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * A service to manage multiple clients that want to access the fingerprint HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * fingerprint -related events.
+ *
+ * @hide
+ */
+public class FingerprintService extends SystemService {
+ private final String TAG = "FingerprintService";
+ private static final boolean DEBUG = true;
+ private ArrayMap<IBinder, ClientData> mClients = new ArrayMap<IBinder, ClientData>();
+
+ private static final int MSG_NOTIFY = 10;
+
+ Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_NOTIFY:
+ handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+ break;
+
+ default:
+ Slog.w(TAG, "Unknown message:" + msg.what);
+ }
+ }
+ };
+ private Context mContext;
+
+ private static final int STATE_IDLE = 0;
+ private static final int STATE_LISTENING = 1;
+ private static final int STATE_ENROLLING = 2;
+ private static final int STATE_REMOVING = 3;
+ private static final long MS_PER_SEC = 1000;
+ public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
+ public static final String ENROLL_FINGERPRINT = "android.permission.ENROLL_FINGERPRINT";
+
+ private static final class ClientData {
+ public IFingerprintServiceReceiver receiver;
+ int state;
+ int userId;
+ public TokenWatcher tokenWatcher;
+ IBinder getToken() { return tokenWatcher.getToken(); }
+ }
+
+ private class TokenWatcher implements IBinder.DeathRecipient {
+ WeakReference<IBinder> token;
+
+ TokenWatcher(IBinder token) {
+ this.token = new WeakReference<IBinder>(token);
+ }
+
+ IBinder getToken() { return token.get(); }
+ public void binderDied() {
+ mClients.remove(token);
+ this.token = null;
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ if (token != null) {
+ if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
+ mClients.remove(token);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+
+ public FingerprintService(Context context) {
+ super(context);
+ mContext = context;
+ nativeInit(this);
+ }
+
+ // TODO: Move these into separate process
+ // JNI methods to communicate from FingerprintManagerService to HAL
+ native int nativeEnroll(int timeout);
+ native int nativeEnrollCancel();
+ native int nativeRemove(int fingerprintId);
+ native int nativeOpenHal();
+ native int nativeCloseHal();
+ native void nativeInit(FingerprintService service);
+
+ // JNI methods for communicating from HAL to clients
+ void notify(int msg, int arg1, int arg2) {
+ mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+ }
+
+ void handleNotify(int msg, int arg1, int arg2) {
+ Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")");
+ for (int i = 0; i < mClients.size(); i++) {
+ ClientData clientData = mClients.valueAt(i);
+ if (clientData == null || clientData.receiver == null) {
+ if (DEBUG) Slog.v(TAG, "clientData at " + i + " is invalid!!");
+ continue;
+ }
+ switch (msg) {
+ case FingerprintManager.FINGERPRINT_ERROR: {
+ final int error = arg1;
+ try {
+ clientData.receiver.onError(error);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ }
+ break;
+ case FingerprintManager.FINGERPRINT_ACQUIRED: {
+ final int acquireInfo = arg1;
+ try {
+ clientData.receiver.onAcquired(acquireInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_PROCESSED: {
+ final int fingerId = arg1;
+ try {
+ clientData.receiver.onProcessed(fingerId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
+ final int fingerId = arg1;
+ final int remaining = arg2;
+ if (clientData.state == STATE_ENROLLING) {
+ // Only send enroll updates to clients that are actually enrolling
+ try {
+ clientData.receiver.onEnrollResult(fingerId, remaining);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ // Update the database with new finger id.
+ // TODO: move to client code (Settings)
+ if (remaining == 0) {
+ FingerprintUtils.addFingerprintIdForUser(fingerId,
+ mContext.getContentResolver(), clientData.userId);
+ clientData.state = STATE_IDLE; // Nothing left to do
+ }
+ } else {
+ if (DEBUG) Slog.w(TAG, "Client not enrolling");
+ break;
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
+ int fingerId = arg1;
+ if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
+ FingerprintUtils.removeFingerprintIdForUser(fingerId,
+ mContext.getContentResolver(), clientData.userId);
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onRemoved(fingerId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ }
+ clientData.state = STATE_LISTENING;
+ }
+ break;
+ }
+ }
+ }
+
+ void startEnroll(IBinder token, long timeout, int userId) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_ENROLLING;
+ nativeEnroll((int) (timeout / MS_PER_SEC));
+ } else {
+ Slog.w(TAG, "enroll(): No listener registered");
+ }
+ }
+
+ void startEnrollCancel(IBinder token, int userId) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_LISTENING;
+ nativeEnrollCancel();
+ } else {
+ Slog.w(TAG, "enrollCancel(): No listener registered");
+ }
+ }
+
+ // Remove all fingerprints for the given user.
+ void startRemove(IBinder token, int fingerId, int userId) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_REMOVING;
+ // The fingerprint id will be removed when we get confirmation from the HAL
+ int result = nativeRemove(fingerId);
+ if (result != 0) {
+ Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
+ }
+ } else {
+ Slog.w(TAG, "remove(" + token + "): No listener registered");
+ }
+ }
+
+ void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
+ if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
+ if (mClients.get(token) == null) {
+ ClientData clientData = new ClientData();
+ clientData.state = STATE_LISTENING;
+ clientData.receiver = receiver;
+ clientData.userId = userId;
+ clientData.tokenWatcher = new TokenWatcher(token);
+ try {
+ token.linkToDeath(clientData.tokenWatcher, 0);
+ mClients.put(token, clientData);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
+ }
+ } else {
+ if (DEBUG) Slog.v(TAG, "listener already registered for " + token);
+ }
+ }
+
+ void removeListener(IBinder token, int userId) {
+ if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ token.unlinkToDeath(clientData.tokenWatcher, 0);
+ mClients.remove(token);
+ } else {
+ if (DEBUG) Slog.v(TAG, "listener not registered: " + token);
+ }
+ mClients.remove(token);
+ }
+
+ void checkPermission(String permisison) {
+ // TODO
+ }
+
+ private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+ @Override // Binder call
+ public void enroll(IBinder token, long timeout, int userId) {
+ checkPermission(ENROLL_FINGERPRINT);
+ startEnroll(token, timeout, userId);
+ }
+
+ @Override // Binder call
+ public void enrollCancel(IBinder token,int userId) {
+ checkPermission(ENROLL_FINGERPRINT);
+ startEnrollCancel(token, userId);
+ }
+
+ @Override // Binder call
+ public void remove(IBinder token, int fingerprintId, int userId) {
+ checkPermission(ENROLL_FINGERPRINT); // TODO: Maybe have another permission
+ startRemove(token, fingerprintId, userId);
+ }
+
+ @Override // Binder call
+ public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
+ {
+ checkPermission(USE_FINGERPRINT);
+ addListener(token, receiver, userId);
+ }
+
+ @Override // Binder call
+ public void stopListening(IBinder token, int userId) {
+ checkPermission(USE_FINGERPRINT);
+ removeListener(token, userId);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+ nativeOpenHal();
+ }
+
+}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 23cf40b..74eaf2a 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -72,9 +72,9 @@
}
if (!mSource.isInPresetInstallationMode()) {
- int prevActiveInput = mSource.getActiveInput();
+ int prevActiveInput = mSource.getActivePortId();
mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
- if (prevActiveInput != mSource.getActiveInput()) {
+ if (prevActiveInput != mSource.getActivePortId()) {
// TODO: change port input here.
}
invokeCallback(HdmiCec.RESULT_SUCCESS);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 08d7786..f86d655a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -372,15 +372,28 @@
}
/**
- * Returns the ID of the active HDMI port. The active input is the port that has the active
- * routing path connected directly or indirectly under the device hierarchy.
+ * Returns the ID of the active HDMI port. The active port is the one that has the active
+ * routing path connected to it directly or indirectly under the device hierarchy.
*/
- int getActiveInput() {
+ int getActivePortId() {
synchronized (mLock) {
return mService.pathToPortId(mActiveRoutingPath);
}
}
+ /**
+ * Update the active port.
+ *
+ * @param portId the new active port id
+ */
+ void setActivePortId(int portId) {
+ synchronized (mLock) {
+ // We update active routing path instead, since we get the active port id from
+ // the active routing path.
+ mActiveRoutingPath = mService.portIdToPath(portId);
+ }
+ }
+
void updateActiveDevice(int logicalAddress, int physicalAddress) {
synchronized (mLock) {
mActiveSource = logicalAddress;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 92ddd3d..353f603 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -52,6 +52,8 @@
HdmiCecLocalDeviceTv(HdmiControlService service) {
super(service, HdmiCec.DEVICE_TV);
+
+ // TODO: load system audio mode and set it to mSystemAudioMode.
}
@Override
@@ -85,6 +87,60 @@
addAndStartAction(new DeviceSelectAction(this, targetDevice, callback));
}
+ /**
+ * Performs the action routing control.
+ *
+ * @param portId new HDMI port to route to
+ * @param callback callback object to report the result with
+ */
+ void portSelect(int portId, IHdmiControlCallback callback) {
+ assertRunOnServiceThread();
+ if (isInPresetInstallationMode()) {
+ invokeCallback(callback, HdmiCec.RESULT_INCORRECT_MODE);
+ return;
+ }
+ // Make sure this call does not stem from <Active Source> message reception, in
+ // which case the two ports will be the same.
+ if (portId == getActivePortId()) {
+ invokeCallback(callback, HdmiCec.RESULT_SUCCESS);
+ return;
+ }
+ setActivePortId(portId);
+
+ // TODO: Return immediately if the operation is triggered by <Text/Image View On>
+ // TODO: Handle invalid port id / active input which should be treated as an
+ // internal tuner.
+
+ removeAction(RoutingControlAction.class);
+
+ int oldPath = mService.portIdToPath(mService.portIdToPath(getActivePortId()));
+ int newPath = mService.portIdToPath(portId);
+ HdmiCecMessage routingChange =
+ HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
+ mService.sendCecCommand(routingChange);
+ addAndStartAction(new RoutingControlAction(this, newPath, callback));
+ }
+
+ /**
+ * Sends key to a target CEC device.
+ *
+ * @param keyCode key code to send. Defined in {@link KeyEvent}.
+ * @param isPressed true if this is keypress event
+ */
+ void sendKeyEvent(int keyCode, boolean isPressed) {
+ assertRunOnServiceThread();
+ List<SendKeyAction> action = getActions(SendKeyAction.class);
+ if (!action.isEmpty()) {
+ action.get(0).processKeyEvent(keyCode, isPressed);
+ } else {
+ if (isPressed) {
+ addAndStartAction(new SendKeyAction(this, getActiveSource(), keyCode));
+ } else {
+ Slog.w(TAG, "Discard key release event");
+ }
+ }
+ }
+
private static void invokeCallback(IHdmiControlCallback callback, int result) {
try {
callback.onComplete(result);
@@ -174,6 +230,15 @@
}
addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
+
+ // If there is AVR, initiate System Audio Auto initiation action,
+ // which turns on and off system audio according to last system
+ // audio setting.
+ HdmiCecDeviceInfo avrInfo = getAvrDeviceInfo();
+ if (avrInfo != null) {
+ addAndStartAction(new SystemAudioAutoInitiationAction(
+ HdmiCecLocalDeviceTv.this, avrInfo.getLogicalAddress()));
+ }
}
});
addAndStartAction(action);
@@ -456,4 +521,10 @@
hotplugActions.get(0).pollAllDevicesNow();
}
}
+
+ boolean canChangeSystemAudio() {
+ // TODO: implement this.
+ // return true if no system audio control sequence is running.
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 8dbfd85..361a063 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -377,6 +377,17 @@
return buildCommand(src, dest, HdmiCec.MESSAGE_USER_CONTROL_RELEASED);
}
+ /**
+ * Build <Give System Audio Mode Status> command.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildGiveSystemAudioModeStatus(int src, int dest) {
+ return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS);
+ }
+
/***** Please ADD new buildXXX() methods above. ******/
/**
diff --git a/services/core/java/com/android/server/hdmi/HdmiConstants.java b/services/core/java/com/android/server/hdmi/HdmiConstants.java
index 9c60e55..5294506 100644
--- a/services/core/java/com/android/server/hdmi/HdmiConstants.java
+++ b/services/core/java/com/android/server/hdmi/HdmiConstants.java
@@ -95,5 +95,7 @@
static final int POLL_ITERATION_IN_ORDER = 0x10000;
static final int POLL_ITERATION_REVERSE_ORDER = 0x20000;
+ static final int UNKNOWN_VOLUME = -1;
+
private HdmiConstants() { /* cannot be instantiated */ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 10da756..fddb833 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -507,7 +507,7 @@
public void run() {
HdmiCecLocalDeviceTv tv = tv();
if (tv == null) {
- Slog.w(TAG, "Local playback device not available");
+ Slog.w(TAG, "Local tv device not available");
invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
return;
}
@@ -517,6 +517,41 @@
}
@Override
+ public void portSelect(final int portId, final IHdmiControlCallback callback) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ HdmiCecLocalDeviceTv tv = tv();
+ if (tv == null) {
+ Slog.w(TAG, "Local tv device not available");
+ invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+ return;
+ }
+ tv.portSelect(portId, callback);
+ }
+ });
+ }
+
+ @Override
+ public void sendKeyEvent(final int keyCode, final boolean isPressed) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ // TODO: sendKeyEvent is for TV device only for now. Allow other
+ // local devices of different types to use this as well.
+ HdmiCecLocalDeviceTv tv = tv();
+ if (tv == null) {
+ Slog.w(TAG, "Local tv device not available");
+ return;
+ }
+ tv.sendKeyEvent(keyCode, isPressed);
+ }
+ });
+ }
+
+ @Override
public void oneTouchPlay(final IHdmiControlCallback callback) {
enforceAccessPermission();
runOnServiceThread(new Runnable() {
@@ -572,16 +607,6 @@
}
@Override
- public void portSelect(int portId, IHdmiControlCallback callback) {
- // TODO: Implement this
- }
-
- @Override
- public void sendKeyEvent(int keyCode, boolean isPressed) {
- // TODO: Implement this
- }
-
- @Override
public List<HdmiPortInfo> getPortInfo() {
enforceAccessPermission();
return mPortInfo;
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index 2eec846..0d657b2 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -196,7 +196,7 @@
// Called whenever an HDMI input of the TV shall become the active input.
private boolean maybeChangeActiveInput(int path) {
- if (localDevice().getActiveInput() == localDevice().pathToPortId(path)) {
+ if (localDevice().getActivePortId() == localDevice().pathToPortId(path)) {
return false;
}
// TODO: Remember the currently active input
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
new file mode 100644
index 0000000..e4d82ef
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2014 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.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+/**
+ * Action to initiate system audio once AVR is detected on Device discovery action.
+ */
+final class SystemAudioAutoInitiationAction extends FeatureAction {
+ private final int mAvrAddress;
+
+ // State that waits for <System Audio Mode Status> once send
+ // <Give System Audio Mode Status> to AV Receiver.
+ private static final int STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS = 1;
+
+ SystemAudioAutoInitiationAction(HdmiCecLocalDevice source, int avrAddress) {
+ super(source);
+ mAvrAddress = avrAddress;
+ }
+
+ @Override
+ boolean start() {
+ mState = STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS;
+
+ addTimer(mState, TIMEOUT_MS);
+ sendGiveSystemAudioModeStatus();
+ return true;
+ }
+
+ private void sendGiveSystemAudioModeStatus() {
+ sendCommand(HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(getSourceAddress(),
+ mAvrAddress), new SendMessageCallback() {
+ @Override
+ public void onSendCompleted(int error) {
+ if (error != HdmiConstants.SEND_RESULT_SUCCESS) {
+ tv().setSystemAudioMode(false);
+ finish();
+ }
+ }
+ });
+ }
+
+ @Override
+ boolean processCommand(HdmiCecMessage cmd) {
+ if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS) {
+ return false;
+ }
+
+ switch (cmd.getOpcode()) {
+ case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
+ handleSystemAudioModeStatusMessage();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private void handleSystemAudioModeStatusMessage() {
+ // If the last setting is system audio, turn on system audio whatever AVR status is.
+ if (tv().getSystemAudioMode()) {
+ if (canChangeSystemAudio()) {
+ addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true));
+ }
+ } else {
+ // If the last setting is non-system audio, turn off system audio mode
+ // and update system audio status (volume or mute).
+ tv().setSystemAudioMode(false);
+ if (canChangeSystemAudio()) {
+ addAndStartAction(new SystemAudioStatusAction(tv(), mAvrAddress));
+ }
+ }
+ finish();
+ }
+
+ @Override
+ void handleTimerEvent(int state) {
+ if (mState != state) {
+ return;
+ }
+
+ switch (mState) {
+ case STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS:
+ handleSystemAudioModeStatusTimeout();
+ break;
+ }
+ }
+
+ private void handleSystemAudioModeStatusTimeout() {
+ if (tv().getSystemAudioMode()) {
+ if (canChangeSystemAudio()) {
+ addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true));
+ }
+ } else {
+ tv().setSystemAudioMode(false);
+ }
+ finish();
+ }
+
+ private boolean canChangeSystemAudio() {
+ return tv().canChangeSystemAudio();
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
new file mode 100644
index 0000000..75e4fef
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2014 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.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.util.Slog;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+/**
+ * Action to update audio status (volume or mute) of audio amplifier
+ */
+// TODO: refactor SystemAudioMode so that it uses this class instead of internal state.
+final class SystemAudioStatusAction extends FeatureAction {
+ private static final String TAG = "SystemAudioStatusAction";
+
+ // State that waits for <ReportAudioStatus>.
+ private static final int STATE_WAIT_FOR_REPORT_AUDIO_STATUS = 1;
+
+ private final int mAvrAddress;
+
+ SystemAudioStatusAction(HdmiCecLocalDevice source, int avrAddress) {
+ super(source);
+ mAvrAddress = avrAddress;
+ }
+
+ @Override
+ boolean start() {
+ mState = STATE_WAIT_FOR_REPORT_AUDIO_STATUS;
+ addTimer(mState, TIMEOUT_MS);
+ sendGiveAudioStatus();
+ return true;
+ }
+
+ private void sendGiveAudioStatus() {
+ sendCommand(HdmiCecMessageBuilder.buildGiveAudioStatus(getSourceAddress(), mAvrAddress),
+ new SendMessageCallback() {
+ @Override
+ public void onSendCompleted(int error) {
+ if (error != HdmiConstants.SEND_RESULT_SUCCESS) {
+ handleSendGiveAudioStatusFailure();
+ }
+ }
+ });
+ }
+
+ private void handleSendGiveAudioStatusFailure() {
+ // Inform to all application that the audio status (volumn, mute) of
+ // the audio amplifier is unknown.
+ tv().setAudioStatus(false, HdmiConstants.UNKNOWN_VOLUME);
+
+ int uiCommand = tv().getSystemAudioMode()
+ ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION // SystemAudioMode: ON
+ : HdmiConstants.UI_COMMAND_MUTE_FUNCTION; // SystemAudioMode: OFF
+ sendUserControlPressedAndReleased(uiCommand);
+ finish();
+ }
+
+ private void sendUserControlPressedAndReleased(int uiCommand) {
+ sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
+ getSourceAddress(), mAvrAddress, uiCommand));
+ sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
+ getSourceAddress(), mAvrAddress));
+ }
+
+ @Override
+ boolean processCommand(HdmiCecMessage cmd) {
+ if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS) {
+ return false;
+ }
+
+ switch (cmd.getOpcode()) {
+ case HdmiCec.MESSAGE_REPORT_AUDIO_STATUS:
+ handleReportAudioStatus(cmd);
+ return true;
+ }
+
+ return false;
+ }
+
+ private void handleReportAudioStatus(HdmiCecMessage cmd) {
+ byte[] params = cmd.getParams();
+ if (params.length > 0) {
+ boolean mute = (params[0] & 0x80) == 0x80;
+ int volume = params[0] & 0x7F;
+ tv().setAudioStatus(mute, volume);
+
+ if ((tv().getSystemAudioMode() && mute) || (!tv().getSystemAudioMode() && !mute)) {
+ // Toggle AVR's mute status to match with the system audio status.
+ sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
+ }
+ finish();
+ } else {
+ Slog.e(TAG, "Invalid <Report Audio Status> message:" + cmd);
+ handleSendGiveAudioStatusFailure();
+ return;
+ }
+ }
+
+ @Override
+ void handleTimerEvent(int state) {
+ if (mState != state) {
+ return;
+ }
+
+ handleSendGiveAudioStatusFailure();
+ }
+}
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index 4aef2d31..538a252 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -19,19 +19,16 @@
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
-import android.os.BatteryProperty;
-import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.os.BatteryManagerInternal;
import android.os.SystemClock;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.BatteryService;
+import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateChangedListener;
@@ -158,14 +155,10 @@
mContext.registerReceiver(this, filter);
// Initialise tracker state.
- BatteryService batteryService = (BatteryService) ServiceManager.getService("battery");
- if (batteryService != null) {
- mBatteryHealthy = !batteryService.getBatteryLevelLow();
- mCharging = batteryService.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
- } else {
- // Unavailable for some reason, we default to false and let ACTION_BATTERY_[OK,LOW]
- // sort it out.
- }
+ BatteryManagerInternal batteryManagerInternal =
+ LocalServices.getService(BatteryManagerInternal.class);
+ mBatteryHealthy = !batteryManagerInternal.getBatteryLevelLow();
+ mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
}
boolean isOnStablePower() {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index f2db791..2a7b4f6 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -16,12 +16,13 @@
package com.android.server.pm;
-import android.content.BroadcastReceiver;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.util.Log;
import java.util.HashSet;
@@ -30,62 +31,63 @@
/**
* {@hide}
*/
-public class BackgroundDexOptService {
-
+public class BackgroundDexOptService extends JobService {
static final String TAG = "BackgroundDexOptService";
- private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) {
- onIdleStart();
- } else if (Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
- onIdleStop();
- }
- }
- };
-
- final PackageManagerService mPackageManager;
+ static final int BACKGROUND_DEXOPT_JOB = 808;
+ private static ComponentName sDexoptServiceName = new ComponentName(
+ BackgroundDexOptService.class.getPackage().getName(),
+ BackgroundDexOptService.class.getName());
final AtomicBoolean mIdleTime = new AtomicBoolean(false);
- public BackgroundDexOptService(Context context) {
- mPackageManager = (PackageManagerService)ServiceManager.getService("package");
-
- IntentFilter idleMaintenanceFilter = new IntentFilter();
- idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
- idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_END);
- context.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL,
- idleMaintenanceFilter, null, null);
+ public static void schedule(Context context) {
+ JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName)
+ .setRequiresDeviceIdle(true)
+ .setRequiresCharging(true)
+ .build();
+ js.schedule(job);
}
- public boolean onIdleStart() {
+ @Override
+ public boolean onStartJob(JobParameters params) {
Log.i(TAG, "onIdleStart");
- if (mPackageManager.isStorageLow()) {
+ final PackageManagerService pm =
+ (PackageManagerService)ServiceManager.getService("package");
+
+ if (pm.isStorageLow()) {
return false;
}
- final HashSet<String> pkgs = mPackageManager.getPackagesThatNeedDexOpt();
+ final HashSet<String> pkgs = pm.getPackagesThatNeedDexOpt();
if (pkgs == null) {
return false;
}
+
+ final JobParameters jobParams = params;
mIdleTime.set(true);
new Thread("BackgroundDexOptService_DexOpter") {
@Override
public void run() {
for (String pkg : pkgs) {
if (!mIdleTime.get()) {
- break;
+ // stopped while still working, so we need to reschedule
+ schedule(BackgroundDexOptService.this);
+ return;
}
- mPackageManager.performDexOpt(pkg, false);
+ pm.performDexOpt(pkg, false);
}
+ // ran to completion, so we abandon our timeslice and do not reschedule
+ jobFinished(jobParams, false);
}
}.start();
return true;
}
- public void onIdleStop() {
+ @Override
+ public boolean onStopJob(JobParameters params) {
Log.i(TAG, "onIdleStop");
mIdleTime.set(false);
+ return false;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1209386..dc76455 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -42,6 +42,7 @@
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.NativeLibraryHelper.ApkHandle;
import com.android.internal.content.PackageHelper;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -1247,7 +1248,7 @@
}
}
- public static final IPackageManager main(Context context, Installer installer,
+ public static final PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
@@ -2242,11 +2243,12 @@
if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
return null;
}
+ // App code is gone, so we aren't worried about split paths
pkg = new PackageParser.Package(packageName);
pkg.applicationInfo.packageName = packageName;
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
- pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
pkg.applicationInfo.sourceDir = ps.codePathString;
+ pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
pkg.applicationInfo.dataDir =
getDataPathForPackage(packageName, 0).getPath();
pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
@@ -4081,6 +4083,7 @@
return false;
}
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ // TODO: generate idmap for split APKs
if (mInstaller.idmap(pkg.codePath, opkg.codePath, sharedGid) != 0) {
Slog.e(TAG, "Failed to generate idmap for " + pkg.codePath + " and " + opkg.codePath);
return false;
@@ -4362,23 +4365,30 @@
}
}
- String codePath = null;
+ final String codePath = pkg.codePath;
+ final String[] splitCodePaths = pkg.splitCodePaths;
+
String resPath = null;
+ String[] splitResPaths = null;
if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
if (ps != null && ps.resourcePathString != null) {
resPath = ps.resourcePathString;
+ splitResPaths = deriveSplitResPaths(pkg.splitCodePaths);
} else {
// Should not happen at all. Just log an error.
Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
}
} else {
resPath = pkg.codePath;
+ splitResPaths = pkg.splitCodePaths;
}
- codePath = pkg.codePath;
// Set application objects path explicitly.
pkg.applicationInfo.sourceDir = codePath;
pkg.applicationInfo.publicSourceDir = resPath;
+ pkg.applicationInfo.splitSourceDirs = splitCodePaths;
+ pkg.applicationInfo.splitPublicSourceDirs = splitResPaths;
+
// Note that we invoke the following method only if we are about to unpack an application
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
| SCAN_UPDATE_SIGNATURE, currentTime, user, abiOverride);
@@ -4626,52 +4636,56 @@
}
}
- boolean performed = false;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- String path = pkg.codePath;
- try {
- boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
- pkg.packageName,
- instructionSet,
- defer);
- // There are three basic cases here:
- // 1.) we need to dexopt, either because we are forced or it is needed
- // 2.) we are defering a needed dexopt
- // 3.) we are skipping an unneeded dexopt
- if (forceDex || (!defer && isDexOptNeededInternal)) {
- Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
- pkg.packageName, instructionSet);
- // Note that we ran dexopt, since rerunning will
- // probably just result in an error again.
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ final ArrayList<String> paths = new ArrayList<>();
+ paths.add(pkg.codePath);
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ Collections.addAll(paths, pkg.splitCodePaths);
+ }
+
+ for (String path : paths) {
+ try {
+ boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
+ pkg.packageName, instructionSet, defer);
+ // There are three basic cases here:
+ // 1.) we need to dexopt, either because we are forced or it is needed
+ // 2.) we are defering a needed dexopt
+ // 3.) we are skipping an unneeded dexopt
+ if (forceDex || (!defer && isDexOptNeededInternal)) {
+ Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
+ pkg.packageName, instructionSet);
+ // Note that we ran dexopt, since rerunning will
+ // probably just result in an error again.
+ pkg.mDexOptNeeded = false;
+ if (ret < 0) {
+ return DEX_OPT_FAILED;
+ }
+ return DEX_OPT_PERFORMED;
+ }
+ if (defer && isDexOptNeededInternal) {
+ if (mDeferredDexOpt == null) {
+ mDeferredDexOpt = new HashSet<PackageParser.Package>();
+ }
+ mDeferredDexOpt.add(pkg);
+ return DEX_OPT_DEFERRED;
+ }
pkg.mDexOptNeeded = false;
- if (ret < 0) {
- return DEX_OPT_FAILED;
- }
- return DEX_OPT_PERFORMED;
+ return DEX_OPT_SKIPPED;
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Apk not found for dexopt: " + path);
+ return DEX_OPT_FAILED;
+ } catch (IOException e) {
+ Slog.w(TAG, "IOException reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (StaleDexCacheError e) {
+ Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception when doing dexopt : ", e);
+ return DEX_OPT_FAILED;
}
- if (defer && isDexOptNeededInternal) {
- if (mDeferredDexOpt == null) {
- mDeferredDexOpt = new HashSet<PackageParser.Package>();
- }
- mDeferredDexOpt.add(pkg);
- return DEX_OPT_DEFERRED;
- }
- pkg.mDexOptNeeded = false;
- return DEX_OPT_SKIPPED;
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Apk not found for dexopt: " + path);
- return DEX_OPT_FAILED;
- } catch (IOException e) {
- Slog.w(TAG, "IOException reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (StaleDexCacheError e) {
- Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (Exception e) {
- Slog.w(TAG, "Exception when doing dexopt : ", e);
- return DEX_OPT_FAILED;
}
}
return DEX_OPT_SKIPPED;
@@ -4819,6 +4833,9 @@
}
if (p != null) {
usesLibraryFiles.add(p.codePath);
+ if (!ArrayUtils.isEmpty(p.splitCodePaths)) {
+ Collections.addAll(usesLibraryFiles, p.splitCodePaths);
+ }
}
}
@@ -4906,7 +4923,7 @@
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) {
final File scanFile = new File(pkg.codePath);
- if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
+ if (pkg.applicationInfo.sourceDir == null ||
pkg.applicationInfo.publicSourceDir == null) {
// Bail out. The resource and code paths haven't been set.
Slog.w(TAG, " Code and resource paths haven't been set correctly");
@@ -5355,6 +5372,7 @@
* only for non-system apps and system app upgrades.
*/
if (pkg.applicationInfo.nativeLibraryDir != null) {
+ // TODO: extend to extract native code from split APKs
final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile);
try {
// Enable gross and lame hacks for apps that are built with old
@@ -5908,6 +5926,8 @@
a.info.packageName = pkg.applicationInfo.packageName;
a.info.sourceDir = pkg.applicationInfo.sourceDir;
a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
+ a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
+ a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
a.info.dataDir = pkg.applicationInfo.dataDir;
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
@@ -9021,6 +9041,10 @@
abstract boolean doPostDeleteLI(boolean delete);
abstract boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException;
+ String[] getSplitCodePaths() {
+ return null;
+ }
+
/**
* Called before the source arguments are copied. This is used mostly
* for MoveParams when it needs to read the source file to put it in the
@@ -9109,10 +9133,6 @@
}
}
- String getCodePath() {
- return codeFileName;
- }
-
void createCopyFile() {
installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
codeFileName = createTempPackageFile(installDir).getPath();
@@ -9268,10 +9288,6 @@
return status;
}
- String getResourcePath() {
- return resourceFileName;
- }
-
private String getResourcePathFromCodePath() {
final String codePath = getCodePath();
if (isFwdLocked()) {
@@ -9302,6 +9318,16 @@
}
@Override
+ String getCodePath() {
+ return codeFileName;
+ }
+
+ @Override
+ String getResourcePath() {
+ return resourceFileName;
+ }
+
+ @Override
String getNativeLibraryPath() {
if (libraryPath == null) {
libraryPath = getLibraryPathFromCodePath();
@@ -9768,6 +9794,20 @@
return codePath.substring(sidx+1, eidx);
}
+ private static String[] deriveSplitResPaths(String[] splitCodePaths) {
+ String[] splitResPaths = null;
+ if (!ArrayUtils.isEmpty(splitCodePaths)) {
+ splitResPaths = new String[splitCodePaths.length];
+ for (int i = 0; i < splitCodePaths.length; i++) {
+ final String splitCodePath = splitCodePaths[i];
+ final String resName = getApkName(splitCodePath) + ".zip";
+ splitResPaths[i] = new File(new File(splitCodePath).getParentFile(),
+ resName).getAbsolutePath();
+ }
+ }
+ return splitResPaths;
+ }
+
class PackageInstalledInfo {
String name;
int uid;
@@ -9824,7 +9864,7 @@
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
} else {
- updateSettingsLI(null, newPackage, installerPackageName, null, null, res);
+ updateSettingsLI(newPackage, installerPackageName, null, null, res);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -9914,8 +9954,7 @@
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
} else {
- updateSettingsLI(deletedPackage, newPackage, installerPackageName, allUsers,
- perUserInstalled, res);
+ updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
updatedSettings = true;
}
}
@@ -10041,8 +10080,7 @@
}
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- updateSettingsLI(deletedPackage, newPackage, installerPackageName, allUsers,
- perUserInstalled, res);
+ updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
updatedSettings = true;
}
}
@@ -10068,21 +10106,13 @@
}
// Utility method used to move dex files during install.
- private int moveDexFilesLI(PackageParser.Package oldPackage, PackageParser.Package newPackage) {
- // TODO: extend to handle splits
- if ((newPackage.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ private int moveDexFilesLI(String oldCodePath, PackageParser.Package newPackage) {
+ // TODO: extend to move split APK dex files
+ if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
-
- boolean moveSuccess = false;
- if (oldPackage != null
- && (oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
- if (mInstaller.movedex(oldPackage.codePath, newPackage.codePath, instructionSet)
- == 0) {
- moveSuccess = true;
- }
- }
-
- if (!moveSuccess) {
+ int retCode = mInstaller.movedex(oldCodePath, newPackage.codePath,
+ instructionSet);
+ if (retCode != 0) {
/*
* Programs may be lazily run through dexopt, so the
* source may not exist. However, something seems to
@@ -10091,19 +10121,17 @@
* remove the target to make sure there isn't a stale
* file from a previous version of the package.
*/
- if (oldPackage != null) {
- mInstaller.rmdex(oldPackage.codePath, instructionSet);
- }
- mInstaller.rmdex(newPackage.codePath, instructionSet);
newPackage.mDexOptNeeded = true;
+ mInstaller.rmdex(oldCodePath, instructionSet);
+ mInstaller.rmdex(newPackage.codePath, instructionSet);
}
}
return PackageManager.INSTALL_SUCCEEDED;
}
- private void updateSettingsLI(PackageParser.Package oldPackage,
- PackageParser.Package newPackage, String installerPackageName, int[] allUsers,
- boolean[] perUserInstalled, PackageInstalledInfo res) {
+ private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
+ int[] allUsers, boolean[] perUserInstalled,
+ PackageInstalledInfo res) {
String pkgName = newPackage.packageName;
synchronized (mPackages) {
//write settings. the installStatus will be incomplete at this stage.
@@ -10113,12 +10141,6 @@
mSettings.writeLPr();
}
- if ((res.returnCode = moveDexFilesLI(oldPackage, newPackage))
- != PackageManager.INSTALL_SUCCEEDED) {
- // Discontinue if moving dex files failed.
- return;
- }
-
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);
synchronized (mPackages) {
@@ -10315,6 +10337,9 @@
pkg.codePath = args.getCodePath();
pkg.applicationInfo.sourceDir = args.getCodePath();
pkg.applicationInfo.publicSourceDir = args.getResourcePath();
+ pkg.applicationInfo.splitSourceDirs = args.getSplitCodePaths();
+ pkg.applicationInfo.splitPublicSourceDirs = deriveSplitResPaths(
+ pkg.applicationInfo.splitSourceDirs);
pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
if (replace) {
replacePackageLI(pkg, parseFlags, scanMode, args.user,
@@ -12857,15 +12882,12 @@
}
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- PackageParser.Package oldPackage = new PackageParser.Package(
- pkg.packageName);
- oldPackage.codePath = pkg.codePath;
pkg.codePath = newCodePath;
// Move dex files around
- if (moveDexFilesLI(oldPackage, pkg) != PackageManager.INSTALL_SUCCEEDED) {
+ if (moveDexFilesLI(oldCodePath, pkg) != PackageManager.INSTALL_SUCCEEDED) {
// Moving of dex files failed. Set
// error code and abort move.
- pkg.codePath = oldPackage.codePath;
+ pkg.codePath = oldCodePath;
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index fb4b8f0..bd80b54 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -19,10 +19,10 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
-import com.android.server.BatteryService;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
+import com.android.server.am.BatteryStatsService;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.Watchdog;
@@ -42,6 +42,7 @@
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.net.Uri;
import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -163,13 +164,14 @@
private static final int POWER_HINT_LOW_POWER_MODE = 5;
private final Context mContext;
+ private final ServiceThread mHandlerThread;
+ private final PowerManagerHandler mHandler;
+
private LightsManager mLightsManager;
- private BatteryService mBatteryService;
+ private BatteryManagerInternal mBatteryManagerInternal;
private DisplayManagerInternal mDisplayManagerInternal;
private IBatteryStats mBatteryStats;
private IAppOpsService mAppOps;
- private ServiceThread mHandlerThread;
- private PowerManagerHandler mHandler;
private WindowManagerPolicy mPolicy;
private Notifier mNotifier;
private WirelessChargerDetector mWirelessChargerDetector;
@@ -429,6 +431,11 @@
public PowerManagerService(Context context) {
super(context);
mContext = context;
+ mHandlerThread = new ServiceThread(TAG,
+ Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
+ mHandlerThread.start();
+ mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
+
synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
@@ -451,39 +458,19 @@
public void onStart() {
publishBinderService(Context.POWER_SERVICE, new BinderService());
publishLocalService(PowerManagerInternal.class, new LocalService());
- }
-
- /**
- * Initialize the power manager.
- * Must be called before any other functions within the power manager are called.
- */
- public void init(LightsManager ls,
- BatteryService bs, IBatteryStats bss,
- IAppOpsService appOps) {
- mLightsManager = ls;
- mBatteryService = bs;
- mBatteryStats = bss;
- mAppOps = appOps;
- mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
- mHandlerThread = new ServiceThread(TAG,
- Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
- mHandlerThread.start();
- mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
- void setPolicy(WindowManagerPolicy policy) {
- synchronized (mLock) {
- mPolicy = policy;
- }
- }
-
- public void systemReady() {
+ public void systemReady(IAppOpsService appOps) {
synchronized (mLock) {
mSystemReady = true;
- mDreamManager = LocalServices.getService(DreamManagerInternal.class);
+ mAppOps = appOps;
+ mDreamManager = getLocalService(DreamManagerInternal.class);
+ mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
+ mPolicy = getLocalService(WindowManagerPolicy.class);
+ mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
@@ -494,6 +481,7 @@
// The notifier runs on the system server's main looper so as not to interfere
// with the animations and other critical functions of the power manager.
+ mBatteryStats = BatteryStatsService.getService();
mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mScreenOnBlocker, mPolicy);
@@ -502,6 +490,8 @@
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
+
+ mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
// Initialize display power management.
@@ -1168,10 +1158,10 @@
final boolean wasPowered = mIsPowered;
final int oldPlugType = mPlugType;
final boolean oldLevelLow = mBatteryLevelLow;
- mIsPowered = mBatteryService.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
- mPlugType = mBatteryService.getPlugType();
- mBatteryLevel = mBatteryService.getBatteryLevel();
- mBatteryLevelLow = mBatteryService.getBatteryLevelLow();
+ mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
+ mPlugType = mBatteryManagerInternal.getPlugType();
+ mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
+ mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
if (DEBUG_SPEW) {
Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
@@ -1254,7 +1244,7 @@
final boolean wasStayOn = mStayOn;
if (mStayOnWhilePluggedInSetting != 0
&& !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
- mStayOn = mBatteryService.isPowered(mStayOnWhilePluggedInSetting);
+ mStayOn = mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting);
} else {
mStayOn = false;
}
@@ -3076,10 +3066,5 @@
mLowPowerModeListeners.add(listener);
}
}
-
- @Override
- public void setPolicy(WindowManagerPolicy policy) {
- PowerManagerService.this.setPolicy(policy);
- }
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index e34f42b..d72ed9e 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -116,6 +116,19 @@
}
}
+ private boolean checkUidChangedLocked(
+ Connection connection, int callingUid, int resolvedUserId) {
+ Integer connectionCallingUid = connection.getCallingUidLocked();
+ Integer connectionResolvedUserId = connection.getResolvedUserIdLocked();
+ if (connectionCallingUid == null || connectionResolvedUserId == null) {
+ return true;
+ }
+ if (connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Create a TvInputHardware object with a specific deviceId. One service at a time can access
* the object, and if more than one process attempts to create hardware with the same deviceId,
@@ -133,8 +146,7 @@
Slog.e(TAG, "Invalid deviceId : " + deviceId);
return null;
}
- if (connection.getCallingUidLocked() != callingUid
- || connection.getResolvedUserIdLocked() != resolvedUserId) {
+ if (checkUidChangedLocked(connection, callingUid, resolvedUserId)) {
TvInputHardwareImpl hardware = new TvInputHardwareImpl(connection.getInfoLocked());
try {
callback.asBinder().linkToDeath(connection, 0);
@@ -160,8 +172,7 @@
return;
}
if (connection.getHardwareLocked() != hardware
- || connection.getCallingUidLocked() != callingUid
- || connection.getResolvedUserIdLocked() != resolvedUserId) {
+ || checkUidChangedLocked(connection, callingUid, resolvedUserId)) {
return;
}
connection.resetLocked(null, null, null, null);
@@ -226,11 +237,11 @@
return mConfigs;
}
- public int getCallingUidLocked() {
+ public Integer getCallingUidLocked() {
return mCallingUid;
}
- public int getResolvedUserIdLocked() {
+ public Integer getResolvedUserIdLocked() {
return mResolvedUserId;
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 6cb6b76..d05d0c7 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -961,8 +961,6 @@
// If the window is not touchable, do not report it but take into account
// the space it takes since the content behind it cannot be touched.
if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
- unaccountedSpace.op(boundsInScreen, unaccountedSpace,
- Region.Op.DIFFERENCE);
continue;
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 45326f7..f1d0585d 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -391,7 +391,7 @@
final WindowStateAnimator winAnimator = unForceHiding.get(i);
winAnimator.setAnimation(a);
winAnimator.mAnimationIsEntrance = true;
- if (startKeyguardExit) {
+ if (startKeyguardExit && mKeyguardGoingAway) {
// Do one time only.
mPolicy.startKeyguardExitAnimation(mCurrentTime + a.getStartOffset(),
a.getDuration());
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2d8a34b..d04d668 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -766,6 +766,8 @@
mDisplaySettings = new DisplaySettings(context);
mDisplaySettings.readSettingsLocked();
+ LocalServices.addService(WindowManagerPolicy.class, mPolicy);
+
mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG));
mFxSession = new SurfaceSession();
@@ -779,7 +781,6 @@
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
- mPowerManagerInternal.setPolicy(mPolicy); // TODO: register as local service instead
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4574caf..765a33d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -195,7 +195,7 @@
= new ArrayList<ActiveAdmin>();
// This is the list of component allowed to start lock task mode.
- final List<ComponentName> mLockTaskComponents = new ArrayList<ComponentName>();
+ final List<String> mLockTaskPackages = new ArrayList<String>();
ComponentName mRestrictionsProvider;
@@ -1014,10 +1014,10 @@
out.endTag(null, "active-password");
}
- for (int i=0; i<policy.mLockTaskComponents.size(); i++) {
- ComponentName component = policy.mLockTaskComponents.get(i);
+ for (int i=0; i<policy.mLockTaskPackages.size(); i++) {
+ String component = policy.mLockTaskPackages.get(i);
out.startTag(null, LOCK_TASK_COMPONENTS_XML);
- out.attribute(null, "name", component.flattenToString());
+ out.attribute(null, "name", component);
out.endTag(null, LOCK_TASK_COMPONENTS_XML);
}
@@ -1077,7 +1077,7 @@
type = parser.next();
int outerDepth = parser.getDepth();
- policy.mLockTaskComponents.clear();
+ policy.mLockTaskPackages.clear();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -1131,9 +1131,7 @@
parser.getAttributeValue(null, "nonletter"));
XmlUtils.skipCurrentTag(parser);
} else if (LOCK_TASK_COMPONENTS_XML.equals(tag)) {
- policy.mLockTaskComponents.add
- (ComponentName.unflattenFromString
- (parser.getAttributeValue(null, "name")));
+ policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
XmlUtils.skipCurrentTag(parser);
} else {
Slog.w(LOG_TAG, "Unknown tag: " + tag);
@@ -3723,38 +3721,40 @@
}
/**
- * Sets which componets may enter lock task mode.
+ * Sets which packages may enter lock task mode.
*
* This function can only be called by the device owner or the profile owner.
* @param components The list of components allowed to enter lock task mode.
*/
- public void setLockTaskComponents(ComponentName[] components) throws SecurityException {
+ public void setLockTaskPackages(String[] packages) throws SecurityException {
// Get the package names of the caller.
int uid = Binder.getCallingUid();
String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
- // Check whether any of the package name is the device owner or the profile owner.
- for (int i=0; i<packageNames.length; i++) {
- String packageName = packageNames[i];
- int userHandle = UserHandle.getUserId(uid);
- String profileOwnerPackage = getProfileOwner(userHandle);
- if (isDeviceOwner(packageName) ||
- (profileOwnerPackage != null && profileOwnerPackage.equals(packageName))) {
+ synchronized (this) {
+ // Check whether any of the package name is the device owner or the profile owner.
+ for (int i=0; i<packageNames.length; i++) {
+ String packageName = packageNames[i];
+ int userHandle = UserHandle.getUserId(uid);
+ String profileOwnerPackage = getProfileOwner(userHandle);
+ if (isDeviceOwner(packageName) ||
+ (profileOwnerPackage != null && profileOwnerPackage.equals(packageName))) {
- // If a package name is the device owner or the profile owner,
- // we update the component list.
- DevicePolicyData policy = getUserData(userHandle);
- policy.mLockTaskComponents.clear();
- if (components != null) {
- for (int j=0; j<components.length; j++) {
- ComponentName component = components[j];
- policy.mLockTaskComponents.add(component);
+ // If a package name is the device owner or the profile owner,
+ // we update the component list.
+ DevicePolicyData policy = getUserData(userHandle);
+ policy.mLockTaskPackages.clear();
+ if (packages != null) {
+ for (int j = 0; j < packages.length; j++) {
+ String pkg = packages[j];
+ policy.mLockTaskPackages.add(pkg);
+ }
}
- }
- // Store the settings persistently.
- saveSettingsLocked(userHandle);
- return;
+ // Store the settings persistently.
+ saveSettingsLocked(userHandle);
+ return;
+ }
}
}
throw new SecurityException();
@@ -3763,30 +3763,33 @@
/**
* This function returns the list of components allowed to start the task lock mode.
*/
- public ComponentName[] getLockTaskComponents() {
- int userHandle = UserHandle.USER_OWNER;
- DevicePolicyData policy = getUserData(userHandle);
- ComponentName[] tempArray = policy.mLockTaskComponents.toArray(new ComponentName[0]);
- return tempArray;
+ public String[] getLockTaskPackages() {
+ synchronized (this) {
+ int userHandle = UserHandle.USER_OWNER;
+ DevicePolicyData policy = getUserData(userHandle);
+ return policy.mLockTaskPackages.toArray(new String[0]);
+ }
}
/**
- * This function lets the caller know whether the given component is allowed to start the
+ * This function lets the caller know whether the given package is allowed to start the
* lock task mode.
- * @param component The component to check
+ * @param pkg The package to check
*/
- public boolean isLockTaskPermitted(ComponentName component) {
+ public boolean isLockTaskPermitted(String pkg) {
// Get current user's devicepolicy
int uid = Binder.getCallingUid();
int userHandle = UserHandle.getUserId(uid);
DevicePolicyData policy = getUserData(userHandle);
- for (int i=0; i<policy.mLockTaskComponents.size(); i++) {
- ComponentName lockTaskComponent = policy.mLockTaskComponents.get(i);
+ synchronized (this) {
+ for (int i = 0; i < policy.mLockTaskPackages.size(); i++) {
+ String lockTaskPackage = policy.mLockTaskPackages.get(i);
- // If the given component equals one of the component stored our device-owner-set
- // list, we allow this component to start the lock task mode.
- if (lockTaskComponent.getPackageName().equals(component.getPackageName())) {
- return true;
+ // If the given package equals one of the packages stored our list,
+ // we allow this package to start lock task mode.
+ if (lockTaskPackage.equals(pkg)) {
+ return true;
+ }
}
}
return false;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3102cce..0d05c5f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -63,6 +63,7 @@
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
+import com.android.server.fingerprint.FingerprintService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.input.InputManagerService;
import com.android.server.job.JobSchedulerService;
@@ -146,8 +147,13 @@
private PowerManagerService mPowerManagerService;
private ActivityManagerService mActivityManagerService;
private DisplayManagerService mDisplayManagerService;
+ private PackageManagerService mPackageManagerService;
+ private PackageManager mPackageManager;
private ContentResolver mContentResolver;
+ private boolean mOnlyCore;
+ private boolean mFirstBoot;
+
/**
* Called to initialize native system services.
*/
@@ -161,6 +167,7 @@
}
public SystemServer() {
+ // Check for factory test mode.
mFactoryTestMode = FactoryTest.getMode();
}
@@ -243,7 +250,7 @@
startBootstrapServices();
startCoreServices();
startOtherServices();
- } catch (RuntimeException ex) {
+ } catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
@@ -287,36 +294,84 @@
mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
}
+ /**
+ * Starts the small tangle of critical services that are needed to get
+ * the system off the ground. These services have complex mutual dependencies
+ * which is why we initialize them all in one place here. Unless your service
+ * is also entwined in these dependencies, it should be initialized in one of
+ * the other functions.
+ */
private void startBootstrapServices() {
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
mInstaller = mSystemServiceManager.startService(Installer.class);
- // Power manager needs to be started early because other services need it.
- // TODO: The conversion to the new pattern is incomplete. We need to switch
- // the power manager's dependencies over then we can use boot phases to arrange
- // initialization order and remove the mPowerManagerService field.
- mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
-
// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
- }
- private void startCoreServices() {
+ // Power manager needs to be started early because other services need it.
+ // Native daemons may be watching for it to be registered so it must be ready
+ // to handle incoming binder calls immediately (including being able to verify
+ // the permissions for those calls).
+ mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
+
+ // Now that the power manager has been started, let the activity manager
+ // initialize power management features.
+ mActivityManagerService.initPowerManagement();
+
// Display manager is needed to provide display metrics before package manager
// starts up.
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
+
+ // We need the default display before we can initialize the package manager.
+ mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ // Only run "core" apps if we're encrypting the device.
+ String cryptState = SystemProperties.get("vold.decrypt");
+ if (ENCRYPTING_STATE.equals(cryptState)) {
+ Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
+ mOnlyCore = true;
+ } else if (ENCRYPTED_STATE.equals(cryptState)) {
+ Slog.w(TAG, "Device encrypted - only parsing core apps");
+ mOnlyCore = true;
+ }
+
+ // Start the package manager.
+ Slog.i(TAG, "Package Manager");
+ mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
+ mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
+ mFirstBoot = mPackageManagerService.isFirstBoot();
+ mPackageManager = mSystemContext.getPackageManager();
+
+ // Initialize attribute cache used to cache resources from packages.
+ AttributeCache.init(mSystemContext);
+
+ // Set up the Application instance for the system process and get started.
+ mActivityManagerService.setSystemProcess();
}
+ /**
+ * Starts some essential services that are not tangled up in the bootstrap process.
+ */
+ private void startCoreServices() {
+ // Manages LEDs and display backlight.
+ mSystemServiceManager.startService(LightsService.class);
+
+ // Tracks the battery level. Requires LightService.
+ mSystemServiceManager.startService(BatteryService.class);
+ }
+
+ /**
+ * Starts a miscellaneous grab bag of stuff that has yet to be refactored
+ * and organized.
+ */
private void startOtherServices() {
final Context context = mSystemContext;
AccountManagerService accountManager = null;
ContentService contentService = null;
- LightsManager lights = null;
- BatteryService battery = null;
VibratorService vibrator = null;
IAlarmManager alarm = null;
MountService mountService = null;
@@ -326,7 +381,6 @@
ConnectivityService connectivity = null;
NetworkScoreService networkScore = null;
NsdService serviceDiscovery= null;
- IPackageManager pm = null;
WindowManagerService wm = null;
BluetoothManagerService bluetooth = null;
UsbService usb = null;
@@ -339,8 +393,6 @@
ConsumerIrService consumerIr = null;
AudioService audioService = null;
- boolean onlyCore = false;
- boolean firstBoot = false;
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -352,38 +404,12 @@
boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
try {
- Slog.i(TAG, "Telephony Registry");
- telephonyRegistry = new TelephonyRegistry(context);
- ServiceManager.addService("telephony.registry", telephonyRegistry);
-
Slog.i(TAG, "Scheduling Policy");
ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
- AttributeCache.init(context);
-
- // We need the default display before we can initialize the package manager.
- mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
-
- Slog.i(TAG, "Package Manager");
- // Only run "core" apps if we're encrypting the device.
- String cryptState = SystemProperties.get("vold.decrypt");
- if (ENCRYPTING_STATE.equals(cryptState)) {
- Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
- onlyCore = true;
- } else if (ENCRYPTED_STATE.equals(cryptState)) {
- Slog.w(TAG, "Device encrypted - only parsing core apps");
- onlyCore = true;
- }
-
- pm = PackageManagerService.main(context, mInstaller,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
- onlyCore);
- try {
- firstBoot = pm.isFirstBoot();
- } catch (RemoteException e) {
- }
-
- mActivityManagerService.setSystemProcess();
+ Slog.i(TAG, "Telephony Registry");
+ telephonyRegistry = new TelephonyRegistry(context);
+ ServiceManager.addService("telephony.registry", telephonyRegistry);
Slog.i(TAG, "Entropy Mixer");
ServiceManager.addService("entropy", new EntropyMixer(context));
@@ -411,24 +437,10 @@
Slog.i(TAG, "System Content Providers");
mActivityManagerService.installSystemProviders();
- mSystemServiceManager.startService(LightsService.class);
- lights = LocalServices.getService(LightsManager.class);
-
- Slog.i(TAG, "Battery Service");
- battery = new BatteryService(context, lights);
- ServiceManager.addService("battery", battery);
-
Slog.i(TAG, "Vibrator Service");
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
- // TODO: use boot phase
- // only initialize the power service after we have started the
- // lights service, content providers and the battery service.
- mPowerManagerService.init(lights, battery,
- BatteryStatsService.getService(),
- mActivityManagerService.getAppOpsService());
-
Slog.i(TAG, "Consumer IR Service");
consumerIr = new ConsumerIrService(context);
ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
@@ -447,7 +459,7 @@
Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
- !firstBoot, onlyCore);
+ !mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
@@ -521,7 +533,7 @@
}
try {
- pm.performBootDexOpt();
+ mPackageManagerService.performBootDexOpt();
} catch (Throwable e) {
reportWtf("performing boot dexopt", e);
}
@@ -559,13 +571,9 @@
reportWtf("starting LockSettingsService service", e);
}
- try {
- // Always start the Device Policy Manager, so that the API is compatible with
- // API8.
- mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
- } catch (Throwable e) {
- reportWtf("starting DevicePolicyService", e);
- }
+ // Always start the Device Policy Manager, so that the API is compatible with
+ // API8.
+ mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
}
if (!disableSystemUI) {
@@ -636,39 +644,17 @@
reportWtf("starting NetworkPolicy Service", e);
}
- try {
- mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting Wi-Fi P2pService", e);
- }
+ mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
- try {
- mSystemServiceManager.startService(WIFI_PASSPOINT_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting Wi-Fi PasspointService", e);
- }
+ mSystemServiceManager.startService(WIFI_PASSPOINT_SERVICE_CLASS);
- try {
- mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting Wi-Fi Service", e);
- }
+ mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
- try {
- Slog.i(TAG, "Wi-Fi Scanning Service");
- mSystemServiceManager.startService(
+ mSystemServiceManager.startService(
"com.android.server.wifi.WifiScanningService");
- } catch (Throwable e) {
- reportWtf("starting Wi-Fi Scanning Service", e);
- }
-
if (!isEmulator) {
- try {
- mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting Ethernet Service", e);
- }
+ mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
} else {
// Don't start the Ethernet service on the emulator because
// it interferes with qemu's SLIRP emulation, which uses
@@ -712,7 +698,7 @@
* AppWidget Provider. Make sure MountService is completely started
* first before continuing.
*/
- if (mountService != null && !onlyCore) {
+ if (mountService != null && !mOnlyCore) {
mountService.waitForAsecScan();
}
@@ -810,14 +796,11 @@
}
if (!disableNonCoreServices) {
- try {
- if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST) ||
- pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)) {
- // Manage USB host and device support
- mSystemServiceManager.startService(USB_SERVICE_CLASS);
- }
- } catch (Throwable e) {
- reportWtf("starting UsbService", e);
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)
+ || mPackageManager.hasSystemFeature(
+ PackageManager.FEATURE_USB_ACCESSORY)) {
+ // Manage USB host and device support
+ mSystemServiceManager.startService(USB_SERVICE_CLASS);
}
try {
@@ -837,20 +820,12 @@
mSystemServiceManager.startService(JobSchedulerService.class);
if (!disableNonCoreServices) {
- try {
- if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
- mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
- }
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting Backup Service", e);
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
+ mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
}
- try {
- if (pm.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
- mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
- }
- } catch (Throwable e) {
- reportWtf("starting AppWidget Service", e);
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+ mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
}
try {
@@ -860,13 +835,8 @@
reportWtf("starting Recognition Service", e);
}
- try {
- if (pm.hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS)) {
- Slog.i(TAG, "Voice Recognition Service");
- mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
- }
- } catch (Throwable e) {
- reportWtf("starting Voice Recognition Service", e);
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS)) {
+ mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
}
}
@@ -932,45 +902,17 @@
}
}
- try {
- Slog.i(TAG, "IdleMaintenanceService");
- new IdleMaintenanceService(context, battery);
- } catch (Throwable e) {
- reportWtf("starting IdleMaintenanceService", e);
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
+ mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
}
- try {
- if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
- mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
- }
- } catch (Throwable e) {
- reportWtf("starting Print Service", e);
- }
+ mSystemServiceManager.startService(RestrictionsManagerService.class);
- try {
- mSystemServiceManager.startService(RestrictionsManagerService.class);
- } catch (Throwable e) {
- reportWtf("starting RestrictionsManagerService", e);
- }
+ mSystemServiceManager.startService(MediaSessionService.class);
- try {
- mSystemServiceManager.startService(MediaSessionService.class);
- } catch (Throwable e) {
- reportWtf("starting MediaSessionService", e);
- }
+ mSystemServiceManager.startService(HdmiControlService.class);
- try {
- mSystemServiceManager.startService(HdmiControlService.class);
- } catch (Throwable e) {
- reportWtf("starting HdmiControlService", e);
- }
-
- try {
- Slog.i(TAG, "TvInputManagerService");
- mSystemServiceManager.startService(TvInputManagerService.class);
- } catch (Throwable e) {
- reportWtf("starting TvInputManagerService", e);
- }
+ mSystemServiceManager.startService(TvInputManagerService.class);
if (!disableNonCoreServices) {
try {
@@ -981,27 +923,20 @@
reportWtf("starting MediaRouterService", e);
}
- try {
- Slog.i(TAG, "Trust Manager");
- mSystemServiceManager.startService(TrustManagerService.class);
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting TrustManagerService", e);
- }
+ mSystemServiceManager.startService(TrustManagerService.class);
+
+ mSystemServiceManager.startService(FingerprintService.class);
try {
Slog.i(TAG, "BackgroundDexOptService");
- new BackgroundDexOptService(context);
+ BackgroundDexOptService.schedule(context);
} catch (Throwable e) {
reportWtf("starting BackgroundDexOptService", e);
}
+
}
- try {
- Slog.i(TAG, "LauncherAppsService");
- mSystemServiceManager.startService(LauncherAppsService.class);
- } catch (Throwable t) {
- reportWtf("starting LauncherAppsService", t);
- }
+ mSystemServiceManager.startService(LauncherAppsService.class);
}
// Before things start rolling, be sure we have decided whether
@@ -1058,27 +993,26 @@
try {
// TODO: use boot phase
- mPowerManagerService.systemReady();
+ mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
} catch (Throwable e) {
reportWtf("making Power Manager Service ready", e);
}
try {
- pm.systemReady();
+ mPackageManagerService.systemReady();
} catch (Throwable e) {
reportWtf("making Package Manager Service ready", e);
}
try {
// TODO: use boot phase and communicate these flags some other way
- mDisplayManagerService.systemReady(safeMode, onlyCore);
+ mDisplayManagerService.systemReady(safeMode, mOnlyCore);
} catch (Throwable e) {
reportWtf("making Display Manager Service ready", e);
}
// These are needed to propagate to the runnable below.
final MountService mountServiceF = mountService;
- final BatteryService batteryF = battery;
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
final NetworkPolicyManagerService networkPolicyF = networkPolicy;
@@ -1127,11 +1061,6 @@
reportWtf("making Mount Service ready", e);
}
try {
- if (batteryF != null) batteryF.systemReady();
- } catch (Throwable e) {
- reportWtf("making Battery Service ready", e);
- }
- try {
if (networkScoreF != null) networkScoreF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Score Service ready", e);
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index d974509..8a4e123 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -20,15 +20,9 @@
import android.os.Bundle;
import android.telephony.DisconnectCause;
-import android.os.SystemClock;
-
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* A {@link android.app.Service} that provides telephone connections to
diff --git a/telecomm/java/android/telecomm/Subscription.aidl b/telecomm/java/android/telecomm/Subscription.aidl
new file mode 100644
index 0000000..6327fcc
--- /dev/null
+++ b/telecomm/java/android/telecomm/Subscription.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2008 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.telecomm;
+
+/**
+ * {@hide}
+ */
+parcelable Subscription;
diff --git a/telecomm/java/android/telecomm/Subscription.java b/telecomm/java/android/telecomm/Subscription.java
index f187f4d..964db4a 100644
--- a/telecomm/java/android/telecomm/Subscription.java
+++ b/telecomm/java/android/telecomm/Subscription.java
@@ -16,25 +16,169 @@
package android.telecomm;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.Rlog;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import java.util.MissingResourceException;
/**
* Represents a distinct subscription, line of service or call placement method that
- * a {@link ConnectionService} can use to place phone calls.
+ * the system can use to place phone calls.
*/
public class Subscription implements Parcelable {
- public Subscription() {}
+ private static final int NO_DENSITY = -1;
+
+ private static final String LOG_TAG = "Subscription";
+
+ private final ComponentName mComponentName;
+ private final String mId;
+ private final Uri mHandle;
+ private final int mLabelResId;
+ private final int mShortDescriptionResId;
+ private final int mIconResId;
+ private final boolean mIsEnabled;
+ private final boolean mIsSystemDefault;
+
+ public Subscription(
+ ComponentName componentName,
+ String id,
+ Uri handle,
+ int labelResId,
+ int shortDescriptionResId,
+ int iconResId,
+ boolean isEnabled,
+ boolean isSystemDefault) {
+ mComponentName = componentName;
+ mId = id;
+ mHandle = handle;
+ mLabelResId = labelResId;
+ mShortDescriptionResId = shortDescriptionResId;
+ mIconResId = iconResId;
+ mIsSystemDefault = isSystemDefault;
+ mIsEnabled = isEnabled;
+ }
+
+ /**
+ * The {@code ComponentName} of the {@link android.telecomm.ConnectionService} which is
+ * responsible for making phone calls using this {@code Subscription}.
+ *
+ * @return A suitable {@code ComponentName}.
+ */
+ public ComponentName getComponentName() {
+ return mComponentName;
+ }
+
+ /**
+ * A unique identifier for this {@code Subscription}, generated by and meaningful to the
+ * {@link android.telecomm.ConnectionService} that created it.
+ *
+ * @return A unique identifier for this {@code Subscription}.
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * The handle (e.g., a phone number) associated with this {@code Subscription}. This represents
+ * the destination from which outgoing calls using this {@code Subscription} will appear to come
+ * from, if applicable, and the destination to which incoming calls using this
+ * {@code Subscription} may be addressed.
+ *
+ * @return A handle expressed as a {@code Uri}, for example, a phone number.
+ */
+ public Uri getHandle() {
+ return mHandle;
+ }
+
+ /**
+ * A short string label describing this {@code Subscription}.
+ *
+ * @param context The invoking {@code Context}, used for retrieving resources.
+ *
+ * @return A label for this {@code Subscription}.
+ */
+ public String getLabel(Context context) {
+ return getString(context, mLabelResId);
+ }
+
+ /**
+ * A short paragraph describing this {@code Subscription}.
+ *
+ * @param context The invoking {@code Context}, used for retrieving resources.
+ *
+ * @return A description for this {@code Subscription}.
+ */
+ public String getShortDescription(Context context) {
+ return getString(context, mShortDescriptionResId);
+ }
+
+ /**
+ * An icon to represent this {@code Subscription} in a user interface.
+ *
+ * @param context The invoking {@code Context}, used for retrieving resources.
+ *
+ * @return An icon for this {@code Subscription}.
+ */
+ public Drawable getIcon(Context context) {
+ return getIcon(context, mIconResId, NO_DENSITY);
+ }
+
+ /**
+ * An icon to represent this {@code Subscription} in a user interface.
+ *
+ * @param context The invoking {@code Context}, used for retrieving resources.
+ * @param density A display density from {@link DisplayMetrics}.
+ *
+ * @return An icon for this {@code Subscription}.
+ */
+ public Drawable getIcon(Context context, int density) {
+ return getIcon(context, mIconResId, density);
+ }
+
+ /**
+ * Whether this {@code Subscription} is enabled for use.
+ *
+ * @return {@code true} if this {@code Subscription} is enabled.
+ */
+ public boolean isEnabled() {
+ return mIsEnabled;
+ }
+
+ /**
+ * Whether this {@code Subscription} is the system default.
+ *
+ * @return {@code true} if this {@code Subscription} is the system default.
+ */
+ public boolean isSystemDefault() {
+ return mIsSystemDefault;
+ }
public int describeContents() {
return 0;
}
- public void writeToParcel(Parcel out, int flags) {}
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(mComponentName, flags);
+ out.writeString(mId);
+ out.writeString(mHandle != null ? mHandle.toString() : "");
+ out.writeInt(mLabelResId);
+ out.writeInt(mShortDescriptionResId);
+ out.writeInt(mIconResId);
+ out.writeInt(mIsEnabled ? 1 : 0);
+ out.writeInt(mIsSystemDefault ? 1 : 0);
+ }
- public static final Parcelable.Creator<Subscription> CREATOR
- = new Parcelable.Creator<Subscription>() {
+ public static final Creator<Subscription> CREATOR
+ = new Creator<Subscription>() {
public Subscription createFromParcel(Parcel in) {
return new Subscription(in);
}
@@ -44,5 +188,54 @@
}
};
- private Subscription(Parcel in) {}
+ private Subscription(Parcel in) {
+ mComponentName = in.readParcelable(getClass().getClassLoader());
+ mId = in.readString();
+ String uriString = in.readString();
+ mHandle = uriString.length() > 0 ? Uri.parse(uriString) : null;
+ mLabelResId = in.readInt();
+ mShortDescriptionResId = in.readInt();
+ mIconResId = in.readInt();
+ mIsEnabled = in.readInt() == 1;
+ mIsSystemDefault = in.readInt() == 1;
+ }
+
+ private String getString(Context context, int resId) {
+ Context packageContext;
+ try {
+ packageContext = context.createPackageContext(mComponentName.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ if (Rlog.isLoggable(LOG_TAG, Log.WARN)) {
+ Rlog.w(LOG_TAG, "Cannot find package " + mComponentName.getPackageName());
+ }
+ return null;
+ }
+ String result = packageContext.getString(resId);
+ if (result == null && Rlog.isLoggable(LOG_TAG, Log.WARN)) {
+ Rlog.w(LOG_TAG, "Cannot find string " + resId + " in package " +
+ mComponentName.getPackageName());
+ }
+ return result;
+ }
+
+ private Drawable getIcon(Context context, int resId, int density) {
+ Context packageContext;
+ try {
+ packageContext = context.createPackageContext(mComponentName.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ if (Rlog.isLoggable(LOG_TAG, Log.WARN)) {
+ Rlog.w(LOG_TAG, "Cannot find package " + mComponentName.getPackageName());
+ }
+ return null;
+ }
+ try {
+ return density == NO_DENSITY ?
+ packageContext.getResources().getDrawable(resId) :
+ packageContext.getResources().getDrawableForDensity(resId, density);
+ } catch (MissingResourceException e) {
+ Rlog.e(LOG_TAG, "Cannot find icon " + resId + " in package " +
+ mComponentName.getPackageName() + ": " + e.toString());
+ return null;
+ }
+ }
}
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
index 4ca878e..0952097 100644
--- a/telecomm/java/android/telecomm/TelecommConstants.java
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -16,6 +16,7 @@
package android.telecomm;
+import android.content.Intent;
import android.os.Bundle;
import android.telephony.TelephonyManager;
@@ -70,6 +71,13 @@
public static final String EXTRA_PACKAGE_NAME = "package";
/**
+ * Optional extra for {@link Intent#ACTION_CALL} containing a boolean that determines whether
+ * the speakerphone should be automatically turned on for an outgoing call.
+ */
+ public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE =
+ "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
+
+ /**
* Extra for {@link #ACTION_INCOMING_CALL} containing the {@link CallServiceDescriptor} that
* describes the call service to use for the incoming call.
*/
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 638b86a..dc2b869 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -16,6 +16,7 @@
package com.android.internal.telecomm;
+import android.telecomm.Subscription;
import android.content.ComponentName;
/**
@@ -45,4 +46,19 @@
* Returns the component name of the phone application installed on the system partition.
*/
ComponentName getSystemPhoneApplication();
+
+ /**
+ * Gets a list of Subscriptions.
+ */
+ List<Subscription> getSubscriptions();
+
+ /**
+ * Sets the enabled state of a given Subscription.
+ */
+ void setEnabled(in Subscription subscription, boolean enabled);
+
+ /**
+ * Sets a given Subscription as the system default.
+ */
+ void setSystemDefault(in Subscription subscription);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 50bbb1e..3fde36e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -19,15 +19,12 @@
import android.annotation.SystemApi;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.telephony.Rlog;
+import android.telecomm.Subscription;
import android.util.Log;
import com.android.internal.telecomm.ITelecommService;
@@ -40,7 +37,6 @@
import java.io.FileInputStream;
import java.io.IOException;
-import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -302,6 +298,17 @@
public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
/**
+ * The lookup key used with an {@link android.content.Intent#ACTION_CALL} or
+ * {@link android.content.Intent#ACTION_DIAL} {@code Intent} for a {@link Subscription}
+ * object indicating a preference when making a phone connection.
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getParcelableExtra(String)}.
+ */
+ public static final String EXTRA_SUBSCRIPTION = "subscription";
+
+ /**
* Broadcast intent action indicating that a precise call state
* (cellular) on the device has changed.
*
@@ -3112,4 +3119,40 @@
}
return false;
}
+
+ /**
+ * Return a list of Subscriptions that can be used to indicate a preference when making
+ * a phone call.
+ *
+ * @see #EXTRA_SUBSCRIPTION
+ * @return A list of {@code Subscription} objects.
+ */
+ public List<Subscription> getSubscriptions() {
+ try {
+ return getTelecommService().getSubscriptions();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#getSubscriptions", e);
+ }
+ return null;
+ }
+
+ /** @hide */
+ @SystemApi
+ public void setEnabled(Subscription subscription, boolean enabled) {
+ try {
+ getTelecommService().setEnabled(subscription, enabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setEnabled", e);
+ }
+ }
+
+ /** @hide */
+ @SystemApi
+ public void setSystemDefault(Subscription subscription) {
+ try {
+ getTelecommService().setSystemDefault(subscription);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setSystemDefault", e);
+ }
+ }
}
diff --git a/tests/IdleServiceTest/Android.mk b/tests/IdleServiceTest/Android.mk
deleted file mode 100644
index a7879c5..0000000
--- a/tests/IdleServiceTest/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := IdleServiceTest
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
diff --git a/tests/IdleServiceTest/AndroidManifest.xml b/tests/IdleServiceTest/AndroidManifest.xml
deleted file mode 100644
index 16d2324..0000000
--- a/tests/IdleServiceTest/AndroidManifest.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.idleservicetest">
-
- <application>
- <service android:name="TestService"
- android:exported="true"
- android:enabled="true"
- android:permission="android.permission.BIND_IDLE_SERVICE" >
- <intent-filter>
- <action android:name="android.service.idle.IdleService" />
- </intent-filter>
- </service>
-
- <service android:name="CrashingTestService"
- android:exported="true"
- android:enabled="true"
- android:permission="android.permission.BIND_IDLE_SERVICE" >
- <intent-filter>
- <action android:name="android.service.idle.IdleService" />
- </intent-filter>
- </service>
-
- <service android:name="TimeoutTestService"
- android:exported="true"
- android:enabled="true"
- android:permission="android.permission.BIND_IDLE_SERVICE" >
- <intent-filter>
- <action android:name="android.service.idle.IdleService" />
- </intent-filter>
- </service>
-
- <!-- UnpermissionedTestService should never run because it does
- not require the necessary permission in its <service> block -->
- <service android:name="UnpermissionedTestService"
- android:exported="true"
- android:enabled="true" >
- <intent-filter>
- <action android:name="android.service.idle.IdleService" />
- </intent-filter>
- </service>
-
- </application>
-</manifest>
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
deleted file mode 100644
index 022ebcf..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2014 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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.os.Handler;
-import android.util.Log;
-
-public class CrashingTestService extends IdleService {
- static final String TAG = "CrashingTestService";
-
- String mNull = null;
-
- @Override
- public boolean onIdleStart() {
- Log.i(TAG, "Idle maintenance: onIdleStart()");
-
- Handler h = new Handler();
- Runnable r = new Runnable() {
- @Override
- public void run() {
- Log.i(TAG, "Explicitly crashing");
- if (mNull.equals("")) {
- Log.i(TAG, "won't happen");
- }
- }
- };
- Log.i(TAG, "Posting explicit crash in 15 seconds");
- h.postDelayed(r, 15 * 1000);
- return true;
- }
-
- @Override
- public void onIdleStop() {
- Log.i(TAG, "Idle maintenance: onIdleStop()");
- }
-
-}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
deleted file mode 100644
index 7e9805f..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2014 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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.os.Handler;
-import android.util.Log;
-
-public class TestService extends IdleService {
- static final String TAG = "TestService";
-
- @Override
- public boolean onIdleStart() {
- Log.i(TAG, "Idle maintenance: onIdleStart()");
-
- Handler h = new Handler();
- Runnable r = new Runnable() {
- @Override
- public void run() {
- Log.i(TAG, "Explicitly finishing idle");
- finishIdle();
- }
- };
- Log.i(TAG, "Posting explicit finish in 15 seconds");
- h.postDelayed(r, 15 * 1000);
- return true;
- }
-
- @Override
- public void onIdleStop() {
- Log.i(TAG, "Idle maintenance: onIdleStop()");
- }
-
-}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
deleted file mode 100644
index b2ba21b..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2014 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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.util.Log;
-
-public class TimeoutTestService extends IdleService {
- private static final String TAG = "TimeoutTestService";
-
- @Override
- public boolean onIdleStart() {
- Log.i(TAG, "onIdleStart() but anticipating time-slice timeout");
- return true;
- }
-
- @Override
- public void onIdleStop() {
- Log.i(TAG, "onIdleStop() so we're done");
- }
-
-}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java
deleted file mode 100644
index b9fe32b..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2014 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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.util.Log;
-
-// Should never be invoked because its manifest declaration does not
-// require the necessary permission.
-public class UnpermissionedTestService extends IdleService {
- private static final String TAG = "UnpermissionedTestService";
-
- @Override
- public boolean onIdleStart() {
- Log.e(TAG, "onIdleStart() for this service should never be called!");
- return false;
- }
-
- @Override
- public void onIdleStop() {
- Log.e(TAG, "onIdleStop() for this service should never be called!");
- }
-
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
index aec87976..33db3f5 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
@@ -213,22 +213,22 @@
public String venueName;
/** list of network authentication types */
- public List<NetworkAuthType> networkAuthType;
+ public List<NetworkAuthType> networkAuthTypeList;
/** list of roaming consortium OIs */
- public List<String> roamingConsortium;
+ public List<String> roamingConsortiumList;
/** IP address availability */
public IpAddressType ipAddrTypeAvailability;
- /** NAI realm */
- public List<NaiRealm> naiRealm;
+ /** list of NAI realm */
+ public List<NaiRealm> naiRealmList;
- /** 3GPP cellular network */
- public List<CellularNetwork> cellularNetwork;
+ /** list of 3GPP cellular network */
+ public List<CellularNetwork> cellularNetworkList;
- /** fully qualified domain name (FQDN) */
- public List<String> domainName;
+ /** list of fully qualified domain name (FQDN) */
+ public List<String> domainNameList;
/** HS 2.0 operator friendly name */
public String operatorFriendlyName;
@@ -236,10 +236,10 @@
/** HS 2.0 wan metrics */
public WanMetrics wanMetrics;
- /** HS 2.0 list of IP proto port */
- public List<IpProtoPort> connectionCapability;
+ /** list of HS 2.0 IP proto port */
+ public List<IpProtoPort> connectionCapabilityList;
- /** HS 2.0 list of OSU providers */
+ /** list of HS 2.0 OSU providers */
public List<WifiPasspointOsuProvider> osuProviderList;
/**
@@ -292,15 +292,15 @@
sb.append(" venueName: ").append("(")
.append(venueName.replace("\n", "\\n")).append(")");
- if (networkAuthType != null) {
+ if (networkAuthTypeList != null) {
sb.append(" networkAuthType: ");
- for (NetworkAuthType auth : networkAuthType)
+ for (NetworkAuthType auth : networkAuthTypeList)
sb.append("(").append(auth.toString()).append(")");
}
- if (roamingConsortium != null) {
+ if (roamingConsortiumList != null) {
sb.append(" roamingConsortium: ");
- for (String oi : roamingConsortium)
+ for (String oi : roamingConsortiumList)
sb.append("(").append(oi).append(")");
}
@@ -309,21 +309,21 @@
.append(ipAddrTypeAvailability.toString()).append(")");
}
- if (naiRealm != null) {
+ if (naiRealmList != null) {
sb.append(" naiRealm: ");
- for (NaiRealm realm : naiRealm)
+ for (NaiRealm realm : naiRealmList)
sb.append("(").append(realm.toString()).append(")");
}
- if (cellularNetwork != null) {
+ if (cellularNetworkList != null) {
sb.append(" cellularNetwork: ");
- for (CellularNetwork plmn : cellularNetwork)
+ for (CellularNetwork plmn : cellularNetworkList)
sb.append("(").append(plmn.toString()).append(")");
}
- if (domainName != null) {
+ if (domainNameList != null) {
sb.append(" domainName: ");
- for (String fqdn : domainName)
+ for (String fqdn : domainNameList)
sb.append("(").append(fqdn).append(")");
}
@@ -335,9 +335,9 @@
sb.append(" wanMetrics: ").append("(")
.append(wanMetrics.toString()).append(")");
- if (connectionCapability != null) {
+ if (connectionCapabilityList != null) {
sb.append(" connectionCapability: ");
- for (IpProtoPort ip : connectionCapability)
+ for (IpProtoPort ip : connectionCapabilityList)
sb.append("(").append(ip.toString()).append(")");
}
@@ -356,21 +356,21 @@
out.writeString(bssid);
out.writeString(venueName);
- if (networkAuthType == null) {
+ if (networkAuthTypeList == null) {
out.writeInt(0);
} else {
- out.writeInt(networkAuthType.size());
- for (NetworkAuthType auth : networkAuthType) {
+ out.writeInt(networkAuthTypeList.size());
+ for (NetworkAuthType auth : networkAuthTypeList) {
out.writeInt(auth.type);
out.writeString(auth.redirectUrl);
}
}
- if (roamingConsortium == null) {
+ if (roamingConsortiumList == null) {
out.writeInt(0);
} else {
- out.writeInt(roamingConsortium.size());
- for (String oi : roamingConsortium)
+ out.writeInt(roamingConsortiumList.size());
+ for (String oi : roamingConsortiumList)
out.writeString(oi);
}
@@ -380,32 +380,32 @@
out.writeInt(ipAddrTypeAvailability.availability);
}
- if (naiRealm == null) {
+ if (naiRealmList == null) {
out.writeInt(0);
} else {
- out.writeInt(naiRealm.size());
- for (NaiRealm realm : naiRealm) {
+ out.writeInt(naiRealmList.size());
+ for (NaiRealm realm : naiRealmList) {
out.writeInt(realm.encoding);
out.writeString(realm.realm);
}
}
- if (cellularNetwork == null) {
+ if (cellularNetworkList == null) {
out.writeInt(0);
} else {
- out.writeInt(cellularNetwork.size());
- for (CellularNetwork plmn : cellularNetwork) {
+ out.writeInt(cellularNetworkList.size());
+ for (CellularNetwork plmn : cellularNetworkList) {
out.writeString(plmn.mcc);
out.writeString(plmn.mnc);
}
}
- if (domainName == null) {
+ if (domainNameList == null) {
out.writeInt(0);
} else {
- out.writeInt(domainName.size());
- for (String fqdn : domainName)
+ out.writeInt(domainNameList.size());
+ for (String fqdn : domainNameList)
out.writeString(fqdn);
}
@@ -423,11 +423,11 @@
out.writeInt(wanMetrics.lmd);
}
- if (connectionCapability == null) {
+ if (connectionCapabilityList == null) {
out.writeInt(0);
} else {
- out.writeInt(connectionCapability.size());
- for (IpProtoPort ip : connectionCapability) {
+ out.writeInt(connectionCapabilityList.size());
+ for (IpProtoPort ip : connectionCapabilityList) {
out.writeInt(ip.proto);
out.writeInt(ip.port);
out.writeInt(ip.status);
@@ -462,20 +462,20 @@
n = in.readInt();
if (n > 0) {
- p.networkAuthType = new ArrayList<NetworkAuthType>();
+ p.networkAuthTypeList = new ArrayList<NetworkAuthType>();
for (int i = 0; i < n; i++) {
NetworkAuthType auth = new NetworkAuthType();
auth.type = in.readInt();
auth.redirectUrl = in.readString();
- p.networkAuthType.add(auth);
+ p.networkAuthTypeList.add(auth);
}
}
n = in.readInt();
if (n > 0) {
- p.roamingConsortium = new ArrayList<String>();
+ p.roamingConsortiumList = new ArrayList<String>();
for (int i = 0; i < n; i++)
- p.roamingConsortium.add(in.readString());
+ p.roamingConsortiumList.add(in.readString());
}
n = in.readInt();
@@ -486,31 +486,31 @@
n = in.readInt();
if (n > 0) {
- p.naiRealm = new ArrayList<NaiRealm>();
+ p.naiRealmList = new ArrayList<NaiRealm>();
for (int i = 0; i < n; i++) {
NaiRealm realm = new NaiRealm();
realm.encoding = in.readInt();
realm.realm = in.readString();
- p.naiRealm.add(realm);
+ p.naiRealmList.add(realm);
}
}
n = in.readInt();
if (n > 0) {
- p.cellularNetwork = new ArrayList<CellularNetwork>();
+ p.cellularNetworkList = new ArrayList<CellularNetwork>();
for (int i = 0; i < n; i++) {
CellularNetwork plmn = new CellularNetwork();
plmn.mcc = in.readString();
plmn.mnc = in.readString();
- p.cellularNetwork.add(plmn);
+ p.cellularNetworkList.add(plmn);
}
}
n = in.readInt();
if (n > 0) {
- p.domainName = new ArrayList<String>();
+ p.domainNameList = new ArrayList<String>();
for (int i = 0; i < n; i++)
- p.domainName.add(in.readString());
+ p.domainNameList.add(in.readString());
}
p.operatorFriendlyName = in.readString();
@@ -528,13 +528,13 @@
n = in.readInt();
if (n > 0) {
- p.connectionCapability = new ArrayList<IpProtoPort>();
+ p.connectionCapabilityList = new ArrayList<IpProtoPort>();
for (int i = 0; i < n; i++) {
IpProtoPort ip = new IpProtoPort();
ip.proto = in.readInt();
ip.port = in.readInt();
ip.status = in.readInt();
- p.connectionCapability.add(ip);
+ p.connectionCapabilityList.add(ip);
}
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index 2f158c2..e7e6767 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -325,7 +325,7 @@
listener = getListener(message.arg2, true);
if (listener != null) {
ParcelableString str = (ParcelableString) message.obj;
- if (str.string == null)
+ if (str == null || str.string == null)
((OsuRemListener) listener).onBrowserDismiss();
else
((OsuRemListener) listener).onBrowserLaunch(str.string);
@@ -485,7 +485,7 @@
*
* @return The list of credentials
*/
- public List<WifiPasspointCredential> getSavedCredentials() {
+ public List<WifiPasspointCredential> getCredentials() {
return null;
}
@@ -529,7 +529,7 @@
Log.d(TAG, "startOsu end");
}
- public void startUserRemediation(Channel c, OsuRemListener listener) {
+ public void startRemediation(Channel c, OsuRemListener listener) {
}
public void connect(WifiPasspointPolicy policy) {