Merge "Import translations. DO NOT MERGE" into oc-dev
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9af74ba..0925217 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -126,6 +126,14 @@
private static volatile boolean sSystemReady = false;
+
+ private static final int FIRST_START_FATAL_ERROR_CODE = -100;
+ private static final int LAST_START_FATAL_ERROR_CODE = -1;
+ private static final int FIRST_START_SUCCESS_CODE = 0;
+ private static final int LAST_START_SUCCESS_CODE = 99;
+ private static final int FIRST_START_NON_FATAL_ERROR_CODE = 100;
+ private static final int LAST_START_NON_FATAL_ERROR_CODE = 199;
+
/**
* System property to enable task snapshots.
* @hide
@@ -219,53 +227,56 @@
*/
public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
+ // NOTE: Before adding a new start result, please reference the defined ranges to ensure the
+ // result is properly categorized.
+
/**
* Result for IActivityManager.startVoiceActivity: active session is currently hidden.
* @hide
*/
- public static final int START_VOICE_HIDDEN_SESSION = -10;
+ public static final int START_VOICE_HIDDEN_SESSION = FIRST_START_FATAL_ERROR_CODE;
/**
* Result for IActivityManager.startVoiceActivity: active session does not match
* the requesting token.
* @hide
*/
- public static final int START_VOICE_NOT_ACTIVE_SESSION = -9;
+ public static final int START_VOICE_NOT_ACTIVE_SESSION = FIRST_START_FATAL_ERROR_CODE + 1;
/**
* Result for IActivityManager.startActivity: trying to start a background user
* activity that shouldn't be displayed for all users.
* @hide
*/
- public static final int START_NOT_CURRENT_USER_ACTIVITY = -8;
+ public static final int START_NOT_CURRENT_USER_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 2;
/**
* Result for IActivityManager.startActivity: trying to start an activity under voice
* control when that activity does not support the VOICE category.
* @hide
*/
- public static final int START_NOT_VOICE_COMPATIBLE = -7;
+ public static final int START_NOT_VOICE_COMPATIBLE = FIRST_START_FATAL_ERROR_CODE + 3;
/**
* Result for IActivityManager.startActivity: an error where the
* start had to be canceled.
* @hide
*/
- public static final int START_CANCELED = -6;
+ public static final int START_CANCELED = FIRST_START_FATAL_ERROR_CODE + 4;
/**
* Result for IActivityManager.startActivity: an error where the
* thing being started is not an activity.
* @hide
*/
- public static final int START_NOT_ACTIVITY = -5;
+ public static final int START_NOT_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 5;
/**
* Result for IActivityManager.startActivity: an error where the
* caller does not have permission to start the activity.
* @hide
*/
- public static final int START_PERMISSION_DENIED = -4;
+ public static final int START_PERMISSION_DENIED = FIRST_START_FATAL_ERROR_CODE + 6;
/**
* Result for IActivityManager.startActivity: an error where the
@@ -273,49 +284,49 @@
* a result.
* @hide
*/
- public static final int START_FORWARD_AND_REQUEST_CONFLICT = -3;
+ public static final int START_FORWARD_AND_REQUEST_CONFLICT = FIRST_START_FATAL_ERROR_CODE + 7;
/**
* Result for IActivityManager.startActivity: an error where the
* requested class is not found.
* @hide
*/
- public static final int START_CLASS_NOT_FOUND = -2;
+ public static final int START_CLASS_NOT_FOUND = FIRST_START_FATAL_ERROR_CODE + 8;
/**
* Result for IActivityManager.startActivity: an error where the
* given Intent could not be resolved to an activity.
* @hide
*/
- public static final int START_INTENT_NOT_RESOLVED = -1;
+ public static final int START_INTENT_NOT_RESOLVED = FIRST_START_FATAL_ERROR_CODE + 9;
/**
* Result for IActivityManaqer.startActivity: the activity was started
* successfully as normal.
* @hide
*/
- public static final int START_SUCCESS = 0;
+ public static final int START_SUCCESS = FIRST_START_SUCCESS_CODE;
/**
* Result for IActivityManaqer.startActivity: the caller asked that the Intent not
* be executed if it is the recipient, and that is indeed the case.
* @hide
*/
- public static final int START_RETURN_INTENT_TO_CALLER = 1;
+ public static final int START_RETURN_INTENT_TO_CALLER = FIRST_START_SUCCESS_CODE + 1;
/**
* Result for IActivityManaqer.startActivity: activity wasn't really started, but
* a task was simply brought to the foreground.
* @hide
*/
- public static final int START_TASK_TO_FRONT = 2;
+ public static final int START_TASK_TO_FRONT = FIRST_START_SUCCESS_CODE + 2;
/**
* Result for IActivityManaqer.startActivity: activity wasn't really started, but
* the given Intent was given to the existing top activity.
* @hide
*/
- public static final int START_DELIVERED_TO_TOP = 3;
+ public static final int START_DELIVERED_TO_TOP = FIRST_START_SUCCESS_CODE + 3;
/**
* Result for IActivityManaqer.startActivity: request was canceled because
@@ -323,14 +334,15 @@
* (such as pressing home) is performed.
* @hide
*/
- public static final int START_SWITCHES_CANCELED = 4;
+ public static final int START_SWITCHES_CANCELED = FIRST_START_NON_FATAL_ERROR_CODE;
/**
* Result for IActivityManaqer.startActivity: a new activity was attempted to be started
* while in Lock Task Mode.
* @hide
*/
- public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION = 5;
+ public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION =
+ FIRST_START_NON_FATAL_ERROR_CODE + 1;
/**
* Flag for IActivityManaqer.startActivity: do special start mode where
@@ -566,6 +578,22 @@
}
/**
+ * Returns whether the launch was successful.
+ * @hide
+ */
+ public static final boolean isStartResultSuccessful(int result) {
+ return FIRST_START_SUCCESS_CODE <= result && result <= LAST_START_SUCCESS_CODE;
+ }
+
+ /**
+ * Returns whether the launch result was a fatal error.
+ * @hide
+ */
+ public static final boolean isStartResultFatalError(int result) {
+ return FIRST_START_FATAL_ERROR_CODE <= result && result <= LAST_START_FATAL_ERROR_CODE;
+ }
+
+ /**
* Screen compatibility mode: the application most always run in
* compatibility mode.
* @hide
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 69ed439..16cbb7c 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1921,7 +1921,7 @@
/** @hide */
public static void checkStartActivityResult(int res, Object intent) {
- if (res >= ActivityManager.START_SUCCESS) {
+ if (!ActivityManager.isStartResultFatalError(res)) {
return;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ccbd5b4..8a15b1f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,6 +16,8 @@
package android.app;
+import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;
+
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
@@ -42,7 +44,6 @@
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
-import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
@@ -72,6 +73,7 @@
import android.widget.RemoteViews;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.NotificationColorUtil;
import com.android.internal.util.Preconditions;
@@ -2670,6 +2672,19 @@
private static final boolean USE_ONLY_TITLE_IN_LOW_PRIORITY_SUMMARY =
SystemProperties.getBoolean("notifications.only_title", true);
+ /**
+ * The lightness difference that has to be added to the primary text color to obtain the
+ * secondary text color when the background is light.
+ */
+ private static final int LIGHTNESS_TEXT_DIFFERENCE_LIGHT = 20;
+
+ /**
+ * The lightness difference that has to be added to the primary text color to obtain the
+ * secondary text color when the background is dark.
+ * A bit less then the above value, since it looks better on dark backgrounds.
+ */
+ private static final int LIGHTNESS_TEXT_DIFFERENCE_DARK = -10;
+
private Context mContext;
private Notification mN;
private Bundle mUserExtras = new Bundle();
@@ -3836,11 +3851,26 @@
contentView.setTextColor(id, mPrimaryTextColor);
}
- private int getPrimaryTextColor() {
+ /**
+ * @return the primary text color
+ * @hide
+ */
+ @VisibleForTesting
+ public int getPrimaryTextColor() {
ensureColors();
return mPrimaryTextColor;
}
+ /**
+ * @return the secondary text color
+ * @hide
+ */
+ @VisibleForTesting
+ public int getSecondaryTextColor() {
+ ensureColors();
+ return mSecondaryTextColor;
+ }
+
private int getActionBarColor() {
ensureColors();
return mActionBarColor;
@@ -3880,16 +3910,21 @@
double textLum = NotificationColorUtil.calculateLuminance(mForegroundColor);
double contrast = NotificationColorUtil.calculateContrast(mForegroundColor,
backgroundColor);
- boolean textDark = backLum > textLum;
+ // We only respect the given colors if worst case Black or White still has
+ // contrast
+ boolean backgroundLight = backLum > textLum
+ && satisfiesTextContrast(backgroundColor, Color.BLACK)
+ || backLum <= textLum
+ && !satisfiesTextContrast(backgroundColor, Color.WHITE);
if (contrast < 4.5f) {
- if (textDark) {
+ if (backgroundLight) {
mSecondaryTextColor = NotificationColorUtil.findContrastColor(
mForegroundColor,
backgroundColor,
true /* findFG */,
4.5f);
mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
- mSecondaryTextColor, -20);
+ mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_LIGHT);
} else {
mSecondaryTextColor =
NotificationColorUtil.findContrastColorAgainstDark(
@@ -3898,16 +3933,17 @@
true /* findFG */,
4.5f);
mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
- mSecondaryTextColor, 10);
+ mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_DARK);
}
} else {
mPrimaryTextColor = mForegroundColor;
mSecondaryTextColor = NotificationColorUtil.changeColorLightness(
- mPrimaryTextColor, textDark ? 10 : -20);
+ mPrimaryTextColor, backgroundLight ? LIGHTNESS_TEXT_DIFFERENCE_LIGHT
+ : LIGHTNESS_TEXT_DIFFERENCE_DARK);
if (NotificationColorUtil.calculateContrast(mSecondaryTextColor,
backgroundColor) < 4.5f) {
// oh well the secondary is not good enough
- if (textDark) {
+ if (backgroundLight) {
mSecondaryTextColor = NotificationColorUtil.findContrastColor(
mSecondaryTextColor,
backgroundColor,
@@ -3922,7 +3958,9 @@
4.5f);
}
mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
- mSecondaryTextColor, textDark ? -20 : 10);
+ mSecondaryTextColor, backgroundLight
+ ? -LIGHTNESS_TEXT_DIFFERENCE_LIGHT
+ : -LIGHTNESS_TEXT_DIFFERENCE_DARK);
}
}
}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index eae9e1e..c613d97 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -862,10 +862,10 @@
out.writeInt(mAutofillType);
out.writeStringArray(mAutofillHints);
final AutofillValue sanitizedValue;
- if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
- sanitizedValue = mAutofillOverlay.value;
- } else if (writeSensitive) {
+ if (writeSensitive) {
sanitizedValue = mAutofillValue;
+ } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
+ sanitizedValue = mAutofillOverlay.value;
} else {
sanitizedValue = null;
}
@@ -1936,7 +1936,7 @@
}
/** @hide */
- public void dump() {
+ public void dump(boolean showSensitive) {
if (mActivityComponent == null) {
Log.i(TAG, "dump(): calling ensureData() first");
ensureData();
@@ -1949,11 +1949,11 @@
WindowNode node = getWindowNodeAt(i);
Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop()
+ " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle());
- dump(" ", node.getRootViewNode());
+ dump(" ", node.getRootViewNode(), showSensitive);
}
}
- void dump(String prefix, ViewNode node) {
+ void dump(String prefix, ViewNode node, boolean showSensitive) {
Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
+ " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
int id = node.getId();
@@ -1992,12 +1992,15 @@
}
CharSequence text = node.getText();
if (text != null) {
+ final String safeText = node.isSanitized() || showSensitive ? text.toString()
+ : "REDACTED[" + text.length() + " chars]";
Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-"
- + node.getTextSelectionEnd() + "): " + text);
+ + node.getTextSelectionEnd() + "): " + safeText);
Log.i(TAG, prefix + " Text size: " + node.getTextSize() + " , style: #"
+ node.getTextStyle());
Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor())
+ ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
+ Log.i(TAG, prefix + " Input type: " + node.getInputType());
}
String webDomain = node.getWebDomain();
if (webDomain != null) {
@@ -2031,7 +2034,6 @@
Log.i(TAG, prefix + "Autofill info: id= " + autofillId
+ ", type=" + node.getAutofillType()
+ ", options=" + Arrays.toString(node.getAutofillOptions())
- + ", inputType=" + node.getInputType()
+ ", hints=" + Arrays.toString(node.getAutofillHints())
+ ", value=" + node.getAutofillValue()
+ ", sanitized=" + node.isSanitized());
@@ -2043,7 +2045,7 @@
String cprefix = prefix + " ";
for (int i=0; i<NCHILDREN; i++) {
ViewNode cnode = node.getChildAt(i);
- dump(cprefix, cnode);
+ dump(cprefix, cnode, showSensitive);
}
}
}
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 007ea88..3cb59f2 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -111,8 +111,11 @@
/* Minimum flex for a periodic job, in milliseconds. */
private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
- /* Minimum backoff interval for a job, in milliseconds */
- private static final long MIN_BACKOFF_MILLIS = 10 * 1000L; // 10 seconds
+ /**
+ * Minimum backoff interval for a job, in milliseconds
+ * @hide
+ */
+ public static final long MIN_BACKOFF_MILLIS = 10 * 1000L; // 10 seconds
/**
* Query the minimum interval allowed for periodic scheduled jobs. Attempting
@@ -431,7 +434,7 @@
/**
* The amount of time the JobScheduler will wait before rescheduling a failed job. This value
* will be increased depending on the backoff policy specified at job creation time. Defaults
- * to 5 seconds.
+ * to 30 seconds, minimum is currently 10 seconds.
*/
public long getInitialBackoffMillis() {
final long minBackoff = getMinBackoffMillis();
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index c3d6606..f907721 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -330,10 +330,32 @@
* This can be called by an application in {@link #onReceive} to allow
* it to keep the broadcast active after returning from that function.
* This does <em>not</em> change the expectation of being relatively
- * responsive to the broadcast (finishing it within 10s), but does allow
+ * responsive to the broadcast, but does allow
* the implementation to move work related to it over to another thread
* to avoid glitching the main UI thread due to disk IO.
*
+ * <p>As a general rule, broadcast receivers are allowed to run for up to 10 seconds
+ * before they system will consider them non-responsive and ANR the app. Since these usually
+ * execute on the app's main thread, they are already bound by the ~5 second time limit
+ * of various operations that can happen there (not to mention just avoiding UI jank), so
+ * the receive limit is generally not of concern. However, once you use {@goAsync}, though
+ * able to be off the main thread, the broadcast execution limit still applies, and that
+ * includes the time spent between calling this method and ultimately
+ * {@link PendingResult#finish() PendingResult.finish()}.</p>
+ *
+ * <p>If you are taking advantage of this method to have more time to execute, it is useful
+ * to know that the available time can be longer in certain situations. In particular, if
+ * the broadcast you are receiving is not a foreground broadcast (that is, the sender has not
+ * used {@link Intent#FLAG_RECEIVER_FOREGROUND}), then more time is allowed for the receivers
+ * to run, allowing them to execute for 30 seconds or even a bit more. This is something that
+ * receivers should rarely take advantage of (long work should be punted to another system
+ * facility such as {@link android.app.job.JobScheduler}, {@link android.app.Service}, or
+ * see especially {@link android.support.v4.app.JobIntentService}), but can be useful in
+ * certain rare cases where it is necessary to do some work as soon as the broadcast is
+ * delivered. Keep in mind that the work you do here will block further broadcasts until
+ * it completes, so taking advantage of this at all excessively can be counter-productive
+ * and cause later events to be received more slowly.</p>
+ *
* @return Returns a {@link PendingResult} representing the result of
* the active broadcast. The BroadcastRecord itself is no longer active;
* all data and other interaction must go through {@link PendingResult}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9096e44..702b91c 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -623,6 +623,8 @@
void deletePreloadsFileCache();
+ ComponentName getInstantAppResolverComponent();
+
ComponentName getInstantAppResolverSettingsComponent();
ComponentName getInstantAppInstallerComponent();
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index e3e0cc5..f779aeb 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -886,6 +886,11 @@
/**
* Return the max width for icons, in pixels.
+ *
+ * <p> Note that this method returns max width of icon's visible part. Hence, it does not take
+ * into account the inset introduced by {@link AdaptiveIconDrawable}. To calculate bitmap image
+ * to function as {@link AcaptiveIconDrawable}, multiply
+ * 1 + 2 * {@link AdaptiveIconDrawable#getExtraInsetFraction()} to the returned size.
*/
public int getIconMaxWidth() {
try {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index fccc877..8e57e85 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -118,6 +118,15 @@
* @hide
*/
public static final int FINGERPRINT_ERROR_VENDOR = 8;
+
+ /**
+ * The operation was canceled because FINGERPRINT_ERROR_LOCKOUT occurred too many times.
+ * Fingerprint authentication is disabled until the user unlocks with strong authentication
+ * (PIN/Pattern/Password)
+ * @hide
+ */
+ public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;
+
/**
* @hide
*/
@@ -871,9 +880,11 @@
case MSG_REMOVED:
sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
msg.arg2 /* groupId */);
+ break;
case MSG_ENUMERATED:
sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
msg.arg2 /* groupId */);
+ break;
}
}
@@ -1013,6 +1024,9 @@
return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
case FINGERPRINT_ERROR_LOCKOUT:
return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
+ case FINGERPRINT_ERROR_LOCKOUT_PERMANENT:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_lockout_permanent);
case FINGERPRINT_ERROR_VENDOR: {
String[] msgArray = mContext.getResources().getStringArray(
com.android.internal.R.array.fingerprint_error_vendor);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f2df7da..7bd3bf6 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.accounts.AccountManager;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -2129,7 +2130,7 @@
* @return the list of users that were created.
* @hide
*/
- public List<UserInfo> getUsers(boolean excludeDying) {
+ public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
try {
return mService.getUsers(excludeDying);
} catch (RemoteException re) {
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 0e06cd3..f987e4e 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -639,6 +639,11 @@
}
}
+ Object lastContext = mConstructorArgs[0];
+ if (mConstructorArgs[0] == null) {
+ // Fill in the context if not already within inflation.
+ mConstructorArgs[0] = mContext;
+ }
Object[] args = mConstructorArgs;
args[1] = attrs;
@@ -648,6 +653,7 @@
final ViewStub viewStub = (ViewStub) view;
viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
}
+ mConstructorArgs[0] = lastContext;
return view;
} catch (NoSuchMethodException e) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 02ac9bd..d3d753b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2770,6 +2770,7 @@
* 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
* 1 PFLAG3_TEMPORARY_DETACH
* 1 PFLAG3_NO_REVEAL_ON_FOCUS
+ * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT
* |-------|-------|-------|-------|
*/
@@ -2858,14 +2859,6 @@
*/
static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000;
- /**
- * Flag indicating that when layout is completed we should notify
- * that the view was entered for autofill purposes. To minimize
- * showing autofill for views not visible to the user we evaluate
- * user visibility which cannot be done until the view is laid out.
- */
- static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x4000;
-
static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
static final int SCROLL_INDICATORS_NONE = 0x0000;
@@ -3050,6 +3043,14 @@
*/
private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000;
+ /**
+ * Flag indicating that when layout is completed we should notify
+ * that the view was entered for autofill purposes. To minimize
+ * showing autofill for views not visible to the user we evaluate
+ * user visibility which cannot be done until the view is laid out.
+ */
+ static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000;
+
/* End of masks for mPrivateFlags3 */
/**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 68c74da..39ac399 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -804,9 +804,26 @@
+ ", value=" + value + ", action=" + action + ", flags=" + flags);
}
+ boolean restartIfNecessary = (flags & FLAG_MANUAL_REQUEST) != 0;
+
try {
- mService.updateSession(mSessionId, id, bounds, value, action, flags,
- mContext.getUserId());
+ if (restartIfNecessary) {
+ final int newId = mService.updateOrRestartSession(mContext.getActivityToken(),
+ mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
+ mCallback != null, flags, mContext.getOpPackageName(), mSessionId, action);
+ if (newId != mSessionId) {
+ if (sDebug) Log.d(TAG, "Session restarted: " + mSessionId + "=>" + newId);
+ mSessionId = newId;
+ final AutofillClient client = getClientLocked();
+ if (client != null) {
+ client.autofillCallbackResetableStateAvailable();
+ }
+ }
+ } else {
+ mService.updateSession(mSessionId, id, bounds, value, action, flags,
+ mContext.getUserId());
+ }
+
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index a12e956..627afa7 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -39,6 +39,9 @@
boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
void updateSession(int sessionId, in AutofillId id, in Rect bounds,
in AutofillValue value, int action, int flags, int userId);
+ int updateOrRestartSession(IBinder activityToken, in IBinder appCallback,
+ in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
+ boolean hasCallback, int flags, String packageName, int sessionId, int action);
void finishSession(int sessionId, int userId);
void cancelSession(int sessionId, int userId);
void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId);
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 5f72fc7..290d811 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -624,8 +624,14 @@
return new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse(String.format("geo:0,0?q=%s", text)));
case TextClassifier.TYPE_URL:
- if (!text.startsWith("https://") && !text.startsWith("http://")) {
- text = "http://" + text;
+ final String httpPrefix = "http://";
+ final String httpsPrefix = "https://";
+ if (text.toLowerCase().startsWith(httpPrefix)) {
+ text = httpPrefix + text.substring(httpPrefix.length());
+ } else if (text.toLowerCase().startsWith(httpsPrefix)) {
+ text = httpsPrefix + text.substring(httpsPrefix.length());
+ } else {
+ text = httpPrefix + text;
}
return new Intent(Intent.ACTION_VIEW, Uri.parse(text))
.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index bb658c1..1fef7cb 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2016,7 +2016,7 @@
/**
* Asynchronously invalidates an action mode using the TextClassifier.
*/
- private void invalidateActionModeAsync() {
+ void invalidateActionModeAsync() {
getSelectionActionModeHelper().invalidateActionModeAsync();
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 59fb02d..8464c6e 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1667,32 +1667,17 @@
int anchorHeight, int drawingLocationY, int screenLocationY, int displayFrameTop,
int displayFrameBottom, boolean allowResize) {
final int winOffsetY = screenLocationY - drawingLocationY;
- final int popupScreenTop = outParams.y + winOffsetY;
- final int spaceBelow = displayFrameBottom - popupScreenTop;
- if (popupScreenTop >= 0 && height <= spaceBelow) {
+ final int anchorTopInScreen = outParams.y + winOffsetY;
+ final int spaceBelow = displayFrameBottom - anchorTopInScreen;
+ if (anchorTopInScreen >= 0 && height <= spaceBelow) {
return true;
}
- final int popupScreenBottom;
- if (mOverlapAnchor) {
- // popupScreenTop equals the anchor's top at this point.
- // When shown above the anchor, an overlapping popup's bottom should be aligned with
- // the anchor's bottom.
- popupScreenBottom = popupScreenTop + anchorHeight;
- } else {
- // popupScreenTop equals the anchor's bottom at this point.
- // When shown above the anchor, a non-overlapping popup's bottom is aligned with
- // the anchor's top.
- popupScreenBottom = popupScreenTop - anchorHeight;
- }
- final int spaceAbove = popupScreenBottom - displayFrameTop;
+ final int spaceAbove = anchorTopInScreen - anchorHeight - displayFrameTop;
if (height <= spaceAbove) {
// Move everything up.
if (mOverlapAnchor) {
- // Add one anchorHeight to compensate for the correction made at the start of
- // findDropDownPosition, and another to account for being aligned to the anchor's
- // bottom, not top.
- yOffset += anchorHeight * 2;
+ yOffset += anchorHeight;
}
outParams.y = drawingLocationY - height + yOffset;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 89182b0..3d54fe7 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -400,6 +400,7 @@
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
mTextClassifier = Preconditions.checkNotNull(textClassifier);
mText = Preconditions.checkNotNull(text).toString();
+ mLastClassificationText = null; // invalidate.
Preconditions.checkArgument(selectionEnd > selectionStart);
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1f54c84..77f27d9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1639,12 +1639,21 @@
boolean canInputOrMove = (mMovement != null || getKeyListener() != null);
boolean clickable = canInputOrMove || isClickable();
boolean longClickable = canInputOrMove || isLongClickable();
+ int focusable = getFocusable();
n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
+ case com.android.internal.R.styleable.View_focusable:
+ TypedValue val = new TypedValue();
+ if (a.getValue(attr, val)) {
+ focusable = (val.type == TypedValue.TYPE_INT_BOOLEAN)
+ ? (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE)
+ : val.data;
+ }
+
case com.android.internal.R.styleable.View_clickable:
clickable = a.getBoolean(attr, clickable);
break;
@@ -1656,6 +1665,13 @@
}
a.recycle();
+ // Some apps were relying on the undefined behavior of focusable winning over
+ // focusableInTouchMode != focusable in TextViews if both were specified in XML (usually
+ // when starting with EditText and setting only focusable=false). To keep those apps from
+ // breaking, re-apply the focusable attribute here.
+ if (focusable != getFocusable()) {
+ setFocusable(focusable);
+ }
setClickable(clickable);
setLongClickable(longClickable);
@@ -10756,7 +10772,11 @@
switch (id) {
case ID_SELECT_ALL:
+ final boolean hadSelection = hasSelection();
selectAllText();
+ if (mEditor != null && hadSelection) {
+ mEditor.invalidateActionModeAsync();
+ }
return true;
case ID_UNDO:
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index cd41f9e..1ba92bf 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -533,6 +533,10 @@
return ColorUtilsFromCompat.calculateContrast(foregroundColor, backgroundColor);
}
+ public static boolean satisfiesTextContrast(int backgroundColor, int foregroundColor) {
+ return NotificationColorUtil.calculateContrast(backgroundColor, foregroundColor) >= 4.5;
+ }
+
/**
* Composite two potentially translucent colors over each other and returns the result.
*/
@@ -540,6 +544,10 @@
return ColorUtilsFromCompat.compositeColors(foreground, background);
}
+ public static boolean isColorLight(int backgroundColor) {
+ return calculateLuminance(backgroundColor) > 0.5f;
+ }
+
/**
* Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
*/
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 214d97c..b529e37 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -60,14 +60,17 @@
static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
jint tileModeX, jint tileModeY) {
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- SkBitmap bitmap;
+ sk_sp<SkImage> image;
if (jbitmap) {
// Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
// we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
- android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap);
+ image = android::bitmap::toBitmap(env, jbitmap).makeImage(nullptr);
}
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
+ if (!image.get()) {
+ SkBitmap bitmap;
+ image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
+ }
sk_sp<SkShader> baseShader = image->makeShader(
(SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
diff --git a/core/proto/android/service/fingerprint.proto b/core/proto/android/service/fingerprint.proto
index 79dba86..f88b762 100644
--- a/core/proto/android/service/fingerprint.proto
+++ b/core/proto/android/service/fingerprint.proto
@@ -54,4 +54,7 @@
// Total number of lockouts.
int32 lockout = 4;
+
+ // Total number of permanent lockouts.
+ int32 lockout_permanent = 5;
}
diff --git a/core/res/res/layout/time_picker_text_input_material.xml b/core/res/res/layout/time_picker_text_input_material.xml
index 76ce826..2bef027 100644
--- a/core/res/res/layout/time_picker_text_input_material.xml
+++ b/core/res/res/layout/time_picker_text_input_material.xml
@@ -37,7 +37,8 @@
android:layout_width="50dp"
android:layout_height="wrap_content"
android:inputType="number"
- android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
+ android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField"
+ android:imeOptions="actionNext"/>
<TextView
android:id="@+id/label_hour"
android:layout_width="wrap_content"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 98356a2..f747d3d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1335,6 +1335,8 @@
<string name="fingerprint_error_canceled">Fingerprint operation canceled.</string>
<!-- Generic error message shown when the fingerprint operation fails because too many attempts have been made. -->
<string name="fingerprint_error_lockout">Too many attempts. Try again later.</string>
+ <!-- Generic error message shown when the fingerprint operation fails because strong authentication is required -->
+ <string name="fingerprint_error_lockout_permanent">Too many attempts. Fingerprint sensor disabled.</string>
<!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
<string name="fingerprint_error_unable_to_process">Try again.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 74779f3..6e3f0e0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2281,6 +2281,7 @@
<java-symbol type="array" name="fingerprint_acquired_vendor" />
<java-symbol type="string" name="fingerprint_error_canceled" />
<java-symbol type="string" name="fingerprint_error_lockout" />
+ <java-symbol type="string" name="fingerprint_error_lockout_permanent" />
<java-symbol type="string" name="fingerprint_name_template" />
<!-- Fingerprint config -->
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
new file mode 100644
index 0000000..ac1ac19
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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;
+
+import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.media.session.MediaSession;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.NotificationColorUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationTest {
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ }
+
+ @Test
+ public void testColorSatisfiedWhenBgDarkTextDarker() {
+ Notification.Builder builder = getMediaNotification();
+ builder.build();
+
+ // An initial guess where the foreground color is actually darker than an already dark bg
+ int backgroundColor = 0xff585868;
+ int initialForegroundColor = 0xff505868;
+ builder.setColorPalette(backgroundColor, initialForegroundColor);
+ int primaryTextColor = builder.getPrimaryTextColor();
+ assertTrue(satisfiesTextContrast(primaryTextColor, backgroundColor));
+ int secondaryTextColor = builder.getSecondaryTextColor();
+ assertTrue(satisfiesTextContrast(secondaryTextColor, backgroundColor));
+ }
+
+ private Notification.Builder getMediaNotification() {
+ MediaSession session = new MediaSession(mContext, "test");
+ return new Notification.Builder(mContext, "color")
+ .setSmallIcon(com.android.internal.R.drawable.emergency_icon)
+ .setContentTitle("Title")
+ .setContentText("Text")
+ .setStyle(new Notification.MediaStyle().setMediaSession(session.getSessionToken()));
+ }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 7b7031b..29447ed 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -124,19 +124,40 @@
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
- isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
+ isTextClassification(
+ classifiedText,
+ TextClassifier.TYPE_EMAIL,
+ "mailto:" + classifiedText));
}
@Test
public void testTextClassifyText_url() {
if (isTextClassifierDisabled()) return;
- String text = "Visit http://www.android.com for more information";
+ String text = "Visit www.android.com for more information";
String classifiedText = "www.android.com";
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
- isTextClassification(classifiedText, TextClassifier.TYPE_URL));
+ isTextClassification(
+ classifiedText,
+ TextClassifier.TYPE_URL,
+ "http://" + classifiedText));
+ }
+
+ @Test
+ public void testTextClassifyText_url_inCaps() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Visit HTTP://ANDROID.COM for more information";
+ String classifiedText = "HTTP://ANDROID.COM";
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+ assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+ isTextClassification(
+ classifiedText,
+ TextClassifier.TYPE_URL,
+ "http://ANDROID.COM"));
}
@Test
@@ -149,7 +170,10 @@
int endIndex = startIndex + classifiedText.length();
LocaleList nullLocales = null;
assertThat(mClassifier.classifyText(text, startIndex, endIndex, nullLocales),
- isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
+ isTextClassification(
+ classifiedText,
+ TextClassifier.TYPE_EMAIL,
+ "mailto:" + classifiedText));
}
@Test
@@ -206,18 +230,23 @@
}
private static Matcher<TextClassification> isTextClassification(
- final String text, final String type) {
+ final String text, final String type, final String intentUri) {
return new BaseMatcher<TextClassification>() {
@Override
public boolean matches(Object o) {
if (o instanceof TextClassification) {
TextClassification result = (TextClassification) o;
final boolean typeRequirementSatisfied;
+ String scheme;
switch (type) {
+ case TextClassifier.TYPE_EMAIL:
+ scheme = result.getIntent().getData().getScheme();
+ typeRequirementSatisfied = "mailto".equals(scheme);
+ break;
case TextClassifier.TYPE_URL:
- String scheme = result.getIntent().getData().getScheme();
- typeRequirementSatisfied = "http".equalsIgnoreCase(scheme)
- || "https".equalsIgnoreCase(scheme);
+ scheme = result.getIntent().getData().getScheme();
+ typeRequirementSatisfied = "http".equals(scheme)
+ || "https".equals(scheme);
break;
default:
typeRequirementSatisfied = true;
@@ -226,7 +255,8 @@
return typeRequirementSatisfied
&& text.equals(result.getText())
&& result.getEntityCount() > 0
- && type.equals(result.getEntity(0));
+ && type.equals(result.getEntity(0))
+ && intentUri.equals(result.getIntent().getDataString());
// TODO: Include other properties.
}
return false;
@@ -235,7 +265,8 @@
@Override
public void describeTo(Description description) {
description.appendText("text=").appendValue(text)
- .appendText(", type=").appendValue(type);
+ .appendText(", type=").appendValue(type)
+ .appendText(", intent.data=").appendValue(intentUri);
}
};
}
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index d765584..b0e486d 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -16,6 +16,7 @@
#include "Bitmap.h"
#include "Caches.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "renderthread/EglManager.h"
#include "renderthread/RenderThread.h"
#include "renderthread/RenderProxy.h"
@@ -34,11 +35,15 @@
#include <private/gui/ComposerService.h>
#include <binder/IServiceManager.h>
#include <ui/PixelFormat.h>
+#include <GrTexture.h>
#include <SkCanvas.h>
+#include <SkImagePriv.h>
namespace android {
+Mutex Bitmap::gLock;
+
static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
int32_t rowBytes32 = SkToS32(rowBytes);
int64_t bigSize = (int64_t) height * rowBytes32;
@@ -317,8 +322,7 @@
return nullptr;
}
SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeSRGB());
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
}
@@ -393,6 +397,7 @@
mPixelStorage.hardware.buffer = buffer;
buffer->incStrong(buffer);
mRowBytes = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride();
+ setImmutable(); // HW bitmaps are always immutable
}
Bitmap::~Bitmap() {
@@ -486,7 +491,13 @@
void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
if (isHardware()) {
- outBitmap->allocPixels(info());
+ if (uirenderer::Properties::isSkiaEnabled()) {
+ // TODO: add color correctness for Skia pipeline - pass null color space for now
+ outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
+ info().colorType(), info().alphaType(), nullptr));
+ } else {
+ outBitmap->allocPixels(info());
+ }
uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
return;
}
@@ -512,4 +523,28 @@
return nullptr;
}
+sk_sp<SkImage> Bitmap::makeImage(const uirenderer::renderthread::RenderThread* renderThread) {
+ AutoMutex _lock(gLock); //TODO: implement lock free solution
+ auto image = mImage;
+ //TODO: use new API SkImage::isValid() instead of SkImage::getTexture()->getContext()
+ if (!image.get() || (image->getTexture() && nullptr == image->getTexture()->getContext())) {
+ if (isHardware() && uirenderer::RenderPipelineType::SkiaGL
+ == uirenderer::Properties::getRenderPipelineType()) {
+ //TODO: add Vulkan support
+ if (renderThread) {
+ image = uirenderer::skiapipeline::SkiaOpenGLPipeline::makeTextureImage(
+ *renderThread, this);
+ } else {
+ image = uirenderer::renderthread::RenderProxy::makeTextureImage(this);
+ }
+ } else {
+ SkBitmap skiaBitmap;
+ getSkBitmapForShaders(&skiaBitmap);
+ image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+ }
+ mImage = image;
+ }
+ return image;
+}
+
} // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index da45f76..621e439 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -22,6 +22,8 @@
#include <SkPixelRef.h>
#include <cutils/compiler.h>
#include <ui/GraphicBuffer.h>
+#include <utils/Mutex.h>
+#include <SkImage.h>
namespace android {
@@ -111,6 +113,13 @@
}
GraphicBuffer* graphicBuffer();
+
+ // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread.
+ // If invoked on the render thread, then RenderThread* argument is required.
+ // If not invoked on the render thread, then RenderThread* must be nullptr.
+ // makeImage is wrapping a gralloc buffer with an EGLImage and is passing a texture to Skia.
+ // This is a temporary implementation until Skia can wrap the gralloc buffer in a SkImage.
+ sk_sp<SkImage> makeImage(const uirenderer::renderthread::RenderThread*);
protected:
virtual bool onNewLockPixels(LockRec* rec) override;
virtual void onUnlockPixels() override { };
@@ -145,6 +154,9 @@
GraphicBuffer* buffer;
} hardware;
} mPixelStorage;
+
+ sk_sp<SkImage> mImage;
+ static Mutex gLock;
};
} //namespace android
\ No newline at end of file
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index ae13131..4885873 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -28,6 +28,8 @@
#include <cutils/properties.h>
#include <strings.h>
+#include <SkImagePriv.h>
+#include <gl/GrGLTypes.h>
using namespace android::uirenderer::renderthread;
@@ -197,6 +199,87 @@
}
}
+static void deleteImageTexture(void* context) {
+ EGLImageKHR EGLimage = reinterpret_cast<EGLImageKHR>(context);
+ if (EGLimage != EGL_NO_IMAGE_KHR) {
+ EGLDisplay display = eglGetCurrentDisplay();
+ if (EGL_NO_DISPLAY == display) {
+ display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+ eglDestroyImageKHR(display, EGLimage);
+ }
+}
+
+sk_sp<SkImage> SkiaOpenGLPipeline::makeTextureImage(
+ const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap) {
+ renderThread.eglManager().initialize();
+
+ GraphicBuffer* buffer = bitmap->graphicBuffer();
+ EGLDisplay display = eglGetCurrentDisplay();
+ if (EGL_NO_DISPLAY == display) {
+ display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+ LOG_ALWAYS_FATAL_IF(!bitmap->isHardware(),
+ "Texture image requires a HW bitmap.");
+ // We use an EGLImage to access the content of the GraphicBuffer
+ // The EGL image is later bound to a 2D texture
+ EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
+ EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+ EGLImageKHR EGLimage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ clientBuffer, imageAttrs);
+ if (EGLimage == EGL_NO_IMAGE_KHR) {
+ ALOGW("Could not create EGL image, err =%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
+ return nullptr;
+ }
+
+ GLuint textureId = 0;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, EGLimage);
+
+ GLenum status = GL_NO_ERROR;
+ while ((status = glGetError()) != GL_NO_ERROR) {
+ ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
+ eglDestroyImageKHR(display, EGLimage);
+ return nullptr;
+ }
+
+ sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
+ grContext->resetContext();
+
+ GrGLTextureInfo textureInfo;
+ textureInfo.fTarget = GL_TEXTURE_EXTERNAL_OES;
+ textureInfo.fID = textureId;
+
+ GrBackendTextureDesc textureDescription;
+ textureDescription.fWidth = bitmap->info().width();
+ textureDescription.fHeight = bitmap->info().height();
+ textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
+ textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&textureInfo);
+ PixelFormat format = buffer->getPixelFormat();
+ switch (format) {
+ case PIXEL_FORMAT_RGBA_8888:
+ textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
+ break;
+ case PIXEL_FORMAT_RGBA_FP16:
+ textureDescription.fConfig = kRGBA_half_GrPixelConfig;
+ break;
+ default:
+ eglDestroyImageKHR(display, EGLimage);
+ return nullptr;
+ }
+
+ // TODO: add color correctness - pass null color space for now
+ sk_sp<SkImage> image = SkImage::MakeFromTexture(grContext.get(), textureDescription,
+ bitmap->info().alphaType(), nullptr, deleteImageTexture, EGLimage);
+ if (!image.get()) {
+ eglDestroyImageKHR(display, EGLimage);
+ return nullptr;
+ }
+ return image;
+}
+
} /* namespace skiapipeline */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 36685dd..f3ce189 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -46,6 +46,8 @@
bool isContextReady() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
+ static sk_sp<SkImage> makeTextureImage(
+ const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap);
private:
renderthread::EglManager& mEglManager;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index a18d264..1a6e709 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -61,6 +61,7 @@
textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
CopyResult copyResult = CopyResult::UnknownError;
+ // TODO: add color correctness - pass null color space for now
sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription));
if (image) {
SkAutoLockPixels alp(*bitmap);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 10c1865..349d4cc 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -155,11 +155,11 @@
GrContext* context = thread.getGrContext();
if (context) {
ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
- SkBitmap skiaBitmap;
- bitmap->getSkBitmap(&skiaBitmap);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
- SkImage_pinAsTexture(image.get(), context);
- SkImage_unpinAsTexture(image.get(), context);
+ auto image = bitmap->makeImage(&thread);
+ if (image.get() && !bitmap->isHardware()) {
+ SkImage_pinAsTexture(image.get(), context);
+ SkImage_unpinAsTexture(image.get(), context);
+ }
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 559d268..5d7bbfa 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -168,11 +168,8 @@
}
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
- SkBitmap skBitmap;
- bitmap.getSkBitmap(&skBitmap);
-
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
- if (!skBitmap.isImmutable()) {
+ sk_sp<SkImage> image = bitmap.makeImage(nullptr);
+ if (!bitmap.isImmutable()) {
mDisplayList->mMutableImages.push_back(image.get());
}
SkPaint tmpPaint;
@@ -181,12 +178,10 @@
void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
SkAutoCanvasRestore acr(&mRecorder, true);
concat(matrix);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
- if (!bitmap.isImmutable()) {
+ sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+ if (!hwuiBitmap.isImmutable()) {
mDisplayList->mMutableImages.push_back(image.get());
}
SkPaint tmpPaint;
@@ -196,12 +191,10 @@
void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
float dstBottom, const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
- if (!bitmap.isImmutable()) {
+ sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+ if (!hwuiBitmap.isImmutable()) {
mDisplayList->mMutableImages.push_back(image.get());
}
SkPaint tmpPaint;
@@ -210,11 +203,8 @@
void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
-
SkCanvas::Lattice lattice;
- NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
+ NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
lattice.fFlags = nullptr;
int numFlags = 0;
@@ -231,8 +221,8 @@
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
- if (!bitmap.isImmutable()) {
+ sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+ if (!hwuiBitmap.isImmutable()) {
mDisplayList->mMutableImages.push_back(image.get());
}
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index a1f1717..5c2ec0e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -693,6 +693,18 @@
}
}
+CREATE_BRIDGE2(makeTextureImage, RenderThread* thread, Bitmap* bitmap) {
+ return args->thread->makeTextureImage(args->bitmap).release();
+}
+
+sk_sp<SkImage> RenderProxy::makeTextureImage(Bitmap* bitmap) {
+ SETUP_TASK(makeTextureImage);
+ args->bitmap = bitmap;
+ args->thread = &RenderThread::getInstance();
+ sk_sp<SkImage> hardwareImage(reinterpret_cast<SkImage*>(staticPostAndWait(task)));
+ return hardwareImage;
+}
+
void RenderProxy::post(RenderTask* task) {
mRenderThread.queue(task);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index a60ed55..97ad796 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -135,6 +135,8 @@
static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap);
+
+ static sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
private:
RenderThread& mRenderThread;
CanvasContext* mContext;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 1450ec9..d62b556 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -17,6 +17,7 @@
#include "RenderThread.h"
#include "../renderstate/RenderState.h"
+#include "../pipeline/skia/SkiaOpenGLPipeline.h"
#include "../pipeline/skia/SkiaOpenGLReadback.h"
#include "CanvasContext.h"
#include "EglManager.h"
@@ -433,6 +434,24 @@
return next;
}
+sk_sp<SkImage> RenderThread::makeTextureImage(Bitmap* bitmap) {
+ auto renderType = Properties::getRenderPipelineType();
+ sk_sp<SkImage> hardwareImage;
+ switch (renderType) {
+ case RenderPipelineType::SkiaGL:
+ hardwareImage = skiapipeline::SkiaOpenGLPipeline::makeTextureImage(*this, bitmap);
+ break;
+ case RenderPipelineType::SkiaVulkan:
+ //TODO: add Vulkan support
+ break;
+ default:
+ LOG_ALWAYS_FATAL("makeTextureImage: canvas context type %d not supported",
+ (int32_t) renderType);
+ break;
+ }
+ return hardwareImage;
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 9bc5985..34542c6 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -33,6 +33,7 @@
namespace android {
+class Bitmap;
class DisplayEventReceiver;
namespace uirenderer {
@@ -104,6 +105,8 @@
VulkanManager& vulkanManager() { return *mVkManager; }
+ sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
+
protected:
virtual bool threadLoop() override;
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index aa6b3c2..fd20d47 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -319,7 +319,7 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Eginbidea esperimentala da eta eragina izan dezake funtzionamenduan."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"<xliff:g id="TIME">%1$s</xliff:g> inguru gelditzen dira"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> gelditzen dira guztiz kargatu arte"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> falta dira guztiz kargatu arte"</string>
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
<string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> inguru gelditzen dira"</string>
<string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
@@ -327,7 +327,7 @@
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
<string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Ezezaguna"</string>
- <string name="battery_info_status_charging" msgid="1705179948350365604">"Kargatzea"</string>
+ <string name="battery_info_status_charging" msgid="1705179948350365604">"Kargatzen"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"kargatzen"</string>
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ez da kargatzen ari"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ez da kargatzen ari"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 5d29ec0..c69f324 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -324,7 +324,7 @@
<string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - encore environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> – Temps restant : <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
- <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> avant une charge complète"</string>
+ <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Batterie en charge"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 929332f..3250d03 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -349,7 +349,7 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Máis grande"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O máis grande"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e suxestións"</string>
+ <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e comentarios"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Insire contrasinal para restablec. en demostración"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index e0157bc..9e7355b 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -21,7 +21,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="wifi_fail_to_scan" msgid="1265540342578081461">"Tidak dapat memindai jaringan"</string>
- <string name="wifi_security_none" msgid="7985461072596594400">"Tidak Ada"</string>
+ <string name="wifi_security_none" msgid="7985461072596594400">"Tidak ada"</string>
<string name="wifi_remembered" msgid="4955746899347821096">"Disimpan"</string>
<string name="wifi_disabled_generic" msgid="4259794910584943386">"Nonaktif"</string>
<string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Kegagalan Konfigurasi IP"</string>
@@ -229,7 +229,7 @@
<string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Monitor Telefoni akan mengumpulkan log jika mendeteksi masalah pada fungsi telefoni/modem dan mengirimkan notifikasi ke pengguna untuk melaporkan bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Masukan"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Gambar"</string>
- <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Render yang dipercepat perangkat keras"</string>
+ <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Render yang dipercepat hardware"</string>
<string name="media_category" msgid="4388305075496848353">"Media"</string>
<string name="debug_monitoring_category" msgid="7640508148375798343">"Memantau"</string>
<string name="strict_mode" msgid="1938795874357830695">"Mode ketat diaktifkan"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 52840e3..12c52812 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -205,10 +205,10 @@
<string name="debug_view_attributes" msgid="6485448367803310384">"Харах тохируулгын шалгалтыг идэвхжүүлэх"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Wi‑Fi идэвхтэй байхад ч гэсэн гар утасны датаг идэвхтэй байлгадаг (сүлжээг түргэн солихын тулд)."</string>
<string name="adb_warning_title" msgid="6234463310896563253">"USB дебаг хийхийг зөвшөөрөх үү?"</string>
- <string name="adb_warning_message" msgid="7316799925425402244">"USB дебаг нь зөвхөн хөгжүүлэлтийн зорилготой. Үүнийг өөрийн компьютер болон төхөөрөмжийн хооронд өгөгдөл хуулах, өөрийн төхөөрөмж дээр мэдэгдэлгүйгээр аппликешн суулгах, лог датаг унших зэрэгт ашиглаж болно."</string>
+ <string name="adb_warning_message" msgid="7316799925425402244">"USB дебаг нь зөвхөн хөгжүүлэлтийн зорилготой. Үүнийг өөрийн компьютер болон төхөөрөмжийн хооронд өгөгдөл хуулах, өөрийн төхөөрөмж дээр мэдэгдэлгүйгээр аппликейшн суулгах, лог датаг унших зэрэгт ашиглаж болно."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Таны өмнө нь зөвшөөрөл өгсөн бүх компьютерээс USB дебаг хандалтыг нь хураах уу?"</string>
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Хөгжлийн тохиргоог зөвшөөрөх үү?"</string>
- <string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликешнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string>
+ <string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликейшнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Апп-г USB-р тулгах"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT-р суулгасан апп-уудыг хорлонтой авиртай эсэхийг шалгах."</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Хэт чанга дуугаралт эсвэл муу тохиргоо зэрэг алсын зайн төхөөрөмжийн дуугаралттай холбоотой асуудлын үед Bluetooth-ийн үнэмлэхүй дууны түвшинг идэвхгүй болго."</string>
@@ -219,12 +219,12 @@
<string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCP шалгах авирыг тохируулах"</string>
<string name="debug_debugging_category" msgid="6781250159513471316">"Согог хайх"</string>
<string name="debug_app" msgid="8349591734751384446">"Согог засах апп сонгоно уу"</string>
- <string name="debug_app_not_set" msgid="718752499586403499">"Дебаг аппликешн тохируулаагүй"</string>
- <string name="debug_app_set" msgid="2063077997870280017">"Согог засах аппликешн: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="select_application" msgid="5156029161289091703">"Аппликешн сонгох"</string>
+ <string name="debug_app_not_set" msgid="718752499586403499">"Дебаг аппликейшн тохируулаагүй"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"Согог засах аппликейшн: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="select_application" msgid="5156029161289091703">"Аппликейшн сонгох"</string>
<string name="no_application" msgid="2813387563129153880">"Юуг ч биш"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Согог засагчийг хүлээх"</string>
- <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Согог засагдсан аппликешн ажиллахын өмнө согог засагчийг хавсаргагдахыг хүлээнэ"</string>
+ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Согог засагдсан аппликейшн ажиллахын өмнө согог засагчийг хавсаргагдахыг хүлээнэ"</string>
<string name="telephony_monitor_switch" msgid="1764958220062121194">"Утасны хяналт"</string>
<string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Утасны хяналт нь утас/модемын ажиллагаанд асуудал илрүүлсэн тохиолдолд лог цуглуулж, хэрэглэгчид алдааг засах мэдэгдэл илгээнэ"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Оруулах"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index a6ad468..ef43134 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -102,8 +102,8 @@
<string name="running_process_item_user_label" msgid="3129887865552025943">"Mtumiaji: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="313159469856372621">"Baadhi ya chaguo-msingi zimewekwa"</string>
<string name="launch_defaults_none" msgid="4241129108140034876">"Hakuna chaguo-misingi zilizowekwa"</string>
- <string name="tts_settings" msgid="8186971894801348327">"Mipangilio ya maandishi kwa hotuba"</string>
- <string name="tts_settings_title" msgid="1237820681016639683">"Kubadilisha maandishi hadi usemi"</string>
+ <string name="tts_settings" msgid="8186971894801348327">"Mipangilio ya kusoma maandishi kwa sauti"</string>
+ <string name="tts_settings_title" msgid="1237820681016639683">"Kipengele cha kusoma maandishi kwa sauti"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Kasi ya kutamka"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Kasi ya kutamkwa kwa maneno"</string>
<string name="tts_default_pitch_title" msgid="6135942113172488671">"Uzito wa sauti"</string>
@@ -117,7 +117,7 @@
<string name="tts_install_data_title" msgid="4264378440508149986">"Sakinisha data ya sauti"</string>
<string name="tts_install_data_summary" msgid="5742135732511822589">"Sakinisha data ya sauti inayohitajika kuunganisha usemi"</string>
<string name="tts_engine_security_warning" msgid="8786238102020223650">"Hotuba hii inawezesha injini huenda ikaweza kukusanya maandishi ambayo yatazungumziwa, ikijumlisha data ya kibinafsi ya nenosiri na namba ya kaddi ya mkopo. Inatoka kwa injini ya <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> Wezesha matumizi ya hotuba hii iliyowezeshwa ya injini?"</string>
- <string name="tts_engine_network_required" msgid="1190837151485314743">"Lugha hii inahitaji muunganisho wa mtandao unaofanya kazi kwa towe ya maandishi hadi sauti."</string>
+ <string name="tts_engine_network_required" msgid="1190837151485314743">"Lugha hii inahitaji muunganisho wa mtandao unaofanya kazi ili kipengele cha kusoma maandishi kwa sauti kifanye kazi."</string>
<string name="tts_default_sample_string" msgid="4040835213373086322">"Huu ni mfano wa usanisi usemaji"</string>
<string name="tts_status_title" msgid="7268566550242584413">"Hali ya lugha chaguo-msingi"</string>
<string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> inaweza kutumiwa kikamilifu"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 0ab296e..3135f1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -204,6 +204,13 @@
return colorAccent;
}
+ public static int getThemeAttr(Context context, int attr) {
+ TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+ int theme = ta.getResourceId(0, 0);
+ ta.recycle();
+ return theme;
+ }
+
public static Drawable getDrawable(Context context, int attr) {
TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
Drawable drawable = ta.getDrawable(0);
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 46fbb24..3a2397f 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -88,12 +88,6 @@
private final Path mClipPath = new Path();
private final Path mTextPath = new Path();
- private int mDarkModeBackgroundColor;
- private int mDarkModeFillColor;
-
- private int mLightModeBackgroundColor;
- private int mLightModeFillColor;
-
public BatteryMeterDrawableBase(Context context, int frameColor) {
mContext = context;
final Resources res = context.getResources();
@@ -156,15 +150,6 @@
mPlusPaint = new Paint(mBoltPaint);
mPlusPoints = loadPoints(res, R.array.batterymeter_plus_points);
- mDarkModeBackgroundColor =
- Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_background);
- mDarkModeFillColor =
- Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_fill);
- mLightModeBackgroundColor =
- Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_background);
- mLightModeFillColor =
- Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_fill);
-
mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
}
@@ -259,16 +244,6 @@
return color;
}
- public void setDarkIntensity(float darkIntensity) {
- if (darkIntensity == mOldDarkIntensity) {
- return;
- }
- int backgroundColor = getBackgroundColor(darkIntensity);
- int fillColor = getFillColor(darkIntensity);
- setColors(fillColor, backgroundColor);
- mOldDarkIntensity = darkIntensity;
- }
-
public void setColors(int fillColor, int backgroundColor) {
mIconTint = fillColor;
mFramePaint.setColor(backgroundColor);
@@ -277,20 +252,6 @@
invalidateSelf();
}
- private int getBackgroundColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
- }
-
- private int getFillColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeFillColor, mDarkModeFillColor);
- }
-
- private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
- return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
- }
-
@Override
public void draw(Canvas c) {
final int level = mLevel;
diff --git a/packages/SystemUI/res/drawable/pip_expand.xml b/packages/SystemUI/res/drawable/pip_expand.xml
new file mode 100644
index 0000000..cdb2ee5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pip_expand.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 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"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="36"
+ android:viewportHeight="36">
+
+ <path
+ android:pathData="M0 0h36v36H0z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M10 21H7v8h8v-3h-5v-5zm-3-6h3v-5h5V7H7v8zm19 11h-5v3h8v-8h-3v5zM21
+7v3h5v5h3V7h-8z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_ll.xml b/packages/SystemUI/res/drawable/pip_expand_ll.xml
deleted file mode 100644
index a8b82b5..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_ll.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 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"
- android:width="60dp"
- android:height="60dp"
- android:viewportWidth="60"
- android:viewportHeight="60">
-
- <path
- android:fillColor="#fff"
- android:pathData="M7.5,52h45a5,5,0,0,0,5-5V12.95A5,5,0,0,0,52.5,8H7.5a5,5,0,0,0-5,4.95V47A5,5,0,0,0,7.5,52Zm-1-5V13a1,1,0,0,1,1-1h45a1,1,0,0,1,1,1V47a1,1,0,0,1-1,1H7.5A1,1,0,0,1,6.5,47Z" />
- <path
- android:pathData="M0,0V60H60V0H0Z" />
- <path
- android:fillColor="#fff"
- android:pathData="M35,39.14v2a1,1,0,0,0,1,1H46.5a1,1,0,0,0,1-1V30.64a1,1,0,0,0-1-1h-2a1,1,0,0,0-1,1v7.5H36A1,1,0,0,0,35,39.14Z" />
- <path
- android:fillColor="#fff"
- android:pathData="M13.5,30.36h2a1,1,0,0,0,1-1v-7.5H24a1,1,0,0,0,1-1v-2a1,1,0,0,0-1-1H13.5a1,1,0,0,0-1,1v10.5A1,1,0,0,0,13.5,30.36Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_lr.xml b/packages/SystemUI/res/drawable/pip_expand_lr.xml
deleted file mode 100644
index 44d97ef..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_lr.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 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"
- android:width="60dp"
- android:height="60dp"
- android:viewportWidth="60"
- android:viewportHeight="60">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M57.5,47V12.95c0-2.75-2.25-4.95-5-4.95h-45c-2.75,0-5,2.2-5,4.95V47c0,2.75,2.25,5,5,5h45
-C55.25,52,57.5,49.75,57.5,47z
-M52.5,48h-45c-0.55,0-1-0.45-1-1V13c0-0.55,0.45-1,1-1h45c0.55,0,1,0.45,1,1v34
-C53.5,47.55,53.05,48,52.5,48z" />
- <path
- android:pathData="M60,0v60H0L0,0L60,0z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M25,39.14v2c0,0.55-0.45,1-1,1H13.5c-0.55,0-1-0.45-1-1v-10.5c0-0.55,0.45-1,1-1h2c0.55,0,1,0.45,1,1v7.5
-H24C24.55,38.14,25,38.59,25,39.14z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M46.5,30.36h-2c-0.55,0-1-0.45-1-1v-7.5H36c-0.55,0-1-0.45-1-1v-2c0-0.55,0.45-1,1-1h10.5
-c0.55,0,1,0.45,1,1v10.5C47.5,29.91,47.05,30.36,46.5,30.36z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_pl.xml b/packages/SystemUI/res/drawable/pip_expand_pl.xml
deleted file mode 100644
index 57b9358..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_pl.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 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"
- android:width="60dp"
- android:height="60dp"
- android:viewportWidth="60"
- android:viewportHeight="60">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M47,2.5H12.95C10.2,2.5,8,4.75,8,7.5v45c0,2.75,2.2,5,4.95,5H47c2.75,0,5-2.25,5-5v-45
-C52,4.75,49.75,2.5,47,2.5z
-M48,7.5v45c0,0.55-0.45,1-1,1H13c-0.55,0-1-0.45-1-1v-45c0-0.55,0.45-1,1-1h34
-C47.55,6.5,48,6.95,48,7.5z" />
- <path
- android:pathData="M0,0l60,0v60H0L0,0z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M39.14,35h2c0.55,0,1,0.45,1,1v10.5c0,0.55-0.45,1-1,1h-10.5c-0.55,0-1-0.45-1-1v-2c0-0.55,0.45-1,1-1h7.5
-V36C38.14,35.45,38.59,35,39.14,35z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M30.36,13.5v2c0,0.55-0.45,1-1,1h-7.5V24c0,0.55-0.45,1-1,1h-2c-0.55,0-1-0.45-1-1V13.5c0-0.55,0.45-1,1-1
-h10.5C29.91,12.5,30.36,12.95,30.36,13.5z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_pr.xml b/packages/SystemUI/res/drawable/pip_expand_pr.xml
deleted file mode 100644
index e34a95d..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_pr.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 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"
- android:width="60dp"
- android:height="60dp"
- android:viewportWidth="60"
- android:viewportHeight="60">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M8,7.5v45c0,2.75,2.25,5,5,5h34.05c2.75,0,4.95-2.25,4.95-5v-45c0-2.75-2.2-5-4.95-5H13
-C10.25,2.5,8,4.75,8,7.5z
-M13,6.5h34c0.55,0,1,0.45,1,1v45c0,0.55-0.45,1-1,1H13c-0.55,0-1-0.45-1-1v-45C12,6.95,12.45,6.5,13,6.5z" />
- <path
- android:pathData="M60,0L0,0l0,60h60V0z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M20.86,35h-2c-0.55,0-1,0.45-1,1v10.5c0,0.55,0.45,1,1,1h10.5c0.55,0,1-0.45,1-1v-2c0-0.55-0.45-1-1-1h-7.5
-V36C21.86,35.45,21.41,35,20.86,35z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M29.64,13.5v2c0,0.55,0.45,1,1,1h7.5V24c0,0.55,0.45,1,1,1h2c0.55,0,1-0.45,1-1V13.5c0-0.55-0.45-1-1-1
-h-10.5C30.09,12.5,29.64,12.95,29.64,13.5z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
index 8c66bab..8b7f692 100644
--- a/packages/SystemUI/res/layout/pip_menu_activity.xml
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -38,6 +38,8 @@
android:layout_height="60dp"
android:layout_gravity="center"
android:contentDescription="@string/pip_phone_expand"
+ android:padding="10dp"
+ android:src="@drawable/pip_expand"
android:background="?android:selectableItemBackgroundBorderless" />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 9a97d60..2e22943 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -40,13 +40,13 @@
android:layout_width="wrap_content"
>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneLightTheme"
+ android:theme="?attr/lightIconTheme"
android:id="@+id/ethernet"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneDarkTheme"
+ android:theme="?attr/darkIconTheme"
android:id="@+id/ethernet_dark"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -79,13 +79,13 @@
android:layout_width="wrap_content"
>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneLightTheme"
+ android:theme="?attr/lightIconTheme"
android:id="@+id/wifi_signal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneDarkTheme"
+ android:theme="?attr/darkIconTheme"
android:id="@+id/wifi_signal_dark"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -120,14 +120,14 @@
android:layout_width="wrap_content"
android:contentDescription="@string/accessibility_no_sims">
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneLightTheme"
+ android:theme="?attr/lightIconTheme"
android:id="@+id/no_sims"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/stat_sys_no_sims"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneDarkTheme"
+ android:theme="?attr/darkIconTheme"
android:id="@+id/no_sims_dark"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index a57b17e..06b945d 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -128,5 +128,8 @@
<!-- The initial color for the scrim. -->
<attr name="scrimColor" format="color" />
</declare-styleable>
+
+ <attr name="lightIconTheme" format="reference" />
+ <attr name="darkIconTheme" format="reference" />
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c00b562..6604b6c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -768,7 +768,7 @@
<!-- The bottom margin of the expand container when there are actions.
Equal to pip_action_size - pip_action_padding. -->
- <dimen name="pip_expand_container_edge_margin">36dp</dimen>
+ <dimen name="pip_expand_container_edge_margin">30dp</dimen>
<dimen name="default_gear_space">18dp</dimen>
<dimen name="cell_overlay_padding">18dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9650cea..44da876 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -290,7 +290,14 @@
<style name="Animation.StatusBar">
</style>
- <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings" />
+ <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
+ <item name="lightIconTheme">@style/DualToneLightTheme</item>
+ <item name="darkIconTheme">@style/DualToneDarkTheme</item>
+ </style>
+ <style name="qs_theme" parent="systemui_theme">
+ <item name="lightIconTheme">@style/QSIconTheme</item>
+ <item name="darkIconTheme">@style/QSIconTheme</item>
+ </style>
<style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:colorAccent">@color/remote_input_accent</item>
@@ -346,6 +353,11 @@
<item name="fillColor">@color/dark_mode_icon_color_dual_tone_fill</item>
<item name="singleToneColor">@color/dark_mode_icon_color_single_tone</item>
</style>
+ <style name="QSIconTheme">
+ <item name="backgroundColor">?android:attr/textColorHint</item>
+ <item name="fillColor">?android:attr/textColorPrimary</item>
+ <item name="singleToneColor">?android:attr/textColorPrimary</item>
+ </style>
<style name="TextAppearance.Volume">
<item name="android:textStyle">normal</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 67a2989..2d30476 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -502,6 +502,12 @@
}
}
+ if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
+ mLockPatternUtils.requireStrongAuth(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+ getCurrentUser());
+ }
+
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 911ef24..9dd39d4 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -17,25 +17,28 @@
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+import android.animation.ArgbEvaluator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.util.ArraySet;
-import android.util.AttributeSet;
-import android.util.TypedValue;
import android.database.ContentObserver;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
-
import android.widget.TextView;
+
+import com.android.settingslib.Utils;
import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -63,6 +66,12 @@
private int mLevel;
private boolean mForceShowPercent;
+ private int mDarkModeBackgroundColor;
+ private int mDarkModeFillColor;
+
+ private int mLightModeBackgroundColor;
+ private int mLightModeFillColor;
+
public BatteryMeterView(Context context) {
this(context, null, 0);
}
@@ -98,6 +107,16 @@
addView(mBatteryIconView, mlp);
updateShowPercent();
+
+ Context dualToneDarkTheme = new ContextThemeWrapper(context,
+ Utils.getThemeAttr(context, R.attr.darkIconTheme));
+ Context dualToneLightTheme = new ContextThemeWrapper(context,
+ Utils.getThemeAttr(context, R.attr.lightIconTheme));
+ mDarkModeBackgroundColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.backgroundColor);
+ mDarkModeFillColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.fillColor);
+ mLightModeBackgroundColor = Utils.getColorAttr(dualToneLightTheme, R.attr.backgroundColor);
+ mLightModeFillColor = Utils.getColorAttr(dualToneLightTheme, R.attr.fillColor);
+
// Init to not dark at all.
onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
}
@@ -107,11 +126,6 @@
updateShowPercent();
}
- // StatusBarIconController reaches in here and adjusts the layout parameters of the icon
- public ImageView getBatteryIconView() {
- return mBatteryIconView;
- }
-
@Override
public boolean hasOverlappingRendering() {
return false;
@@ -170,7 +184,7 @@
private void updatePercentText() {
if (mBatteryPercentView != null) {
mBatteryPercentView.setText(
- NumberFormat.getPercentInstance().format(mLevel/100f));
+ NumberFormat.getPercentInstance().format(mLevel / 100f));
}
}
@@ -224,8 +238,13 @@
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- mDrawable.setDarkIntensity(DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0);
- setTextColor(DarkIconDispatcher.getTint(area, this, tint));
+ float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
+ int foreground = getColorForDarkIntensity(intensity, mLightModeFillColor,
+ mDarkModeFillColor);
+ int background = getColorForDarkIntensity(intensity, mLightModeBackgroundColor,
+ mDarkModeBackgroundColor);
+ mDrawable.setColors(foreground, background);
+ setTextColor(foreground);
}
public void setTextColor(int color) {
@@ -235,8 +254,8 @@
}
}
- public void setRawColors(int fgColor, int bgColor) {
- mDrawable.setColors(fgColor, bgColor);
+ private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+ return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
}
private final class SettingObserver extends ContentObserver {
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 9b74cd6..cdad8ae 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -23,7 +23,7 @@
public interface RecentsComponent {
void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
- void toggleRecents(Display display);
+ void toggleRecents();
void preloadRecents();
void showNextAffiliatedTask();
void showPrevAffiliatedTask();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 5eb483d..f198229 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -64,7 +64,7 @@
options.setTaskOverlay(true, false /* canResume */);
final int result = startActivityAsUser(intent, options.toBundle(), UserHandle.USER_CURRENT);
- if (result >= ActivityManager.START_SUCCESS) {
+ if (ActivityManager.isStartResultSuccessful(result)) {
// OK
} else {
// Starting the activity inside the task failed. We can't be sure why, so to be
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 65f24cf..766914c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -303,7 +303,6 @@
mMenuContainerAnimator.cancel();
}
notifyMenuStateChange(menuState);
- updateExpandButtonFromBounds(stackBounds, movementBounds);
mMenuContainerAnimator = new AnimatorSet();
ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
mMenuContainer.getAlpha(), 1f);
@@ -388,24 +387,6 @@
}
}
- private void updateExpandButtonFromBounds(Rect stackBounds, Rect movementBounds) {
- if (stackBounds == null) {
- return;
- }
-
- boolean isLandscapePip = stackBounds.width() > stackBounds.height();
- boolean left = stackBounds.left < movementBounds.centerX();
- boolean top = stackBounds.top < movementBounds.centerY();
- boolean expandL = (left && top) || (!left && !top);
- int iconResId;
- if (isLandscapePip) {
- iconResId = expandL ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr;
- } else {
- iconResId = expandL ? R.drawable.pip_expand_pl : R.drawable.pip_expand_pr;
- }
- mExpandButton.setImageResource(iconResId);
- }
-
private void setActions(Rect stackBounds, List<RemoteAction> actions) {
mActions.clear();
mActions.addAll(actions);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 5b54d85..30240c3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -168,8 +168,7 @@
void onConfigurationChanged(Context context) {
Resources res = context.getResources();
mDefaultTitle = res.getString(R.string.pip_notification_unknown_title);
- mDefaultIconResId = res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
- ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr;
+ mDefaultIconResId = R.drawable.pip_expand;
if (mNotified) {
// update notification
notifyPipNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 5cf049a..3f090f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -23,6 +23,7 @@
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -33,6 +34,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.R.id;
+import com.android.systemui.R.style;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -67,6 +69,7 @@
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
Bundle savedInstanceState) {
+ inflater =inflater.cloneInContext(new ContextThemeWrapper(getContext(), R.style.qs_theme));
return inflater.inflate(R.layout.qs_panel, container, false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index d3bd89f..72dd2da 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -324,14 +324,14 @@
@Override
public void toggleRecentApps() {
- toggleRecents(mContext.getSystemService(WindowManager.class).getDefaultDisplay());
+ toggleRecents();
}
/**
* Toggles the Recents activity.
*/
@Override
- public void toggleRecents(Display display) {
+ public void toggleRecents() {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 7bc591f..c0e4b99 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -222,6 +222,10 @@
getApplicationContext()).onActionEnd(
LatencyTracker.ACTION_TOGGLE_RECENTS));
}
+ DejankUtils.postAfterTraversal(() -> {
+ Recents.getTaskLoader().startLoader(RecentsActivity.this);
+ Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
+ });
return true;
}
};
@@ -376,8 +380,6 @@
// Notify of the next draw
mRecentsView.getViewTreeObserver().addOnPreDrawListener(mRecentsDrawnEventListener);
-
- Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index f431517..8594ec62 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -27,6 +27,7 @@
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.AppGlobals;
@@ -95,6 +96,8 @@
import java.util.Iterator;
import java.util.List;
import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
* Acts as a shim around the real system services that we need to access data from, and provides
@@ -143,6 +146,7 @@
Canvas mBgProtectionCanvas;
private final Handler mHandler = new H();
+ private final ExecutorService mOnewayExecutor = Executors.newSingleThreadExecutor();
/**
* An abstract class to track task stack changes.
@@ -466,13 +470,20 @@
if (mIam == null) return false;
try {
- ActivityManager.StackInfo homeStackInfo = mIam.getStackInfo(
- ActivityManager.StackId.HOME_STACK_ID);
- ActivityManager.StackInfo fullscreenStackInfo = mIam.getStackInfo(
- ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID);
- ActivityManager.StackInfo recentsStackInfo = mIam.getStackInfo(
- ActivityManager.StackId.RECENTS_STACK_ID);
-
+ List<StackInfo> stackInfos = mIam.getAllStackInfos();
+ ActivityManager.StackInfo homeStackInfo = null;
+ ActivityManager.StackInfo fullscreenStackInfo = null;
+ ActivityManager.StackInfo recentsStackInfo = null;
+ for (int i = 0; i < stackInfos.size(); i++) {
+ StackInfo stackInfo = stackInfos.get(i);
+ if (stackInfo.stackId == HOME_STACK_ID) {
+ homeStackInfo = stackInfo;
+ } else if (stackInfo.stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ fullscreenStackInfo = stackInfo;
+ } else if (stackInfo.stackId == RECENTS_STACK_ID) {
+ recentsStackInfo = stackInfo;
+ }
+ }
boolean homeStackVisibleNotOccluded = isStackNotOccluded(homeStackInfo,
fullscreenStackInfo);
boolean recentsStackVisibleNotOccluded = isStackNotOccluded(recentsStackInfo,
@@ -755,10 +766,12 @@
* Sends a message to close other system windows.
*/
public void sendCloseSystemWindows(String reason) {
- try {
- mIam.closeSystemDialogs(reason);
- } catch (RemoteException e) {
- }
+ mOnewayExecutor.submit(() -> {
+ try {
+ mIam.closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ });
}
/**
@@ -998,9 +1011,7 @@
* Returns the current user id.
*/
public int getCurrentUser() {
- if (mAm == null) return 0;
-
- return mAm.getCurrentUser();
+ return KeyguardUpdateMonitor.getCurrentUser();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
index be8da9f..974139a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
@@ -50,6 +50,7 @@
private boolean mLoading;
private boolean mVisible;
private boolean mFlingingFast;
+ private boolean mTaskLoadQueueIdle;
public HighResThumbnailLoader(SystemServicesProxy ssp, Looper looper) {
mMainThreadHandler = new Handler(looper);
@@ -71,13 +72,22 @@
updateLoading();
}
+ /**
+ * Sets whether the other task load queue is idling. Avoid double-loading bitmaps by not
+ * starting this queue until the other queue is idling.
+ */
+ public void setTaskLoadQueueIdle(boolean idle) {
+ mTaskLoadQueueIdle = idle;
+ updateLoading();
+ }
+
@VisibleForTesting
boolean isLoading() {
return mLoading;
}
private void updateLoading() {
- setLoading(mVisible && !mFlingingFast);
+ setLoading(mVisible && !mFlingingFast && mTaskLoadQueueIdle);
}
private void setLoading(boolean loading) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 4b53cd1..7ee0906 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -33,6 +33,7 @@
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
@@ -86,7 +87,7 @@
mCurrentQuietProfiles.clear();
if (currentUserId == UserHandle.USER_CURRENT) {
- currentUserId = ActivityManager.getCurrentUser();
+ currentUserId = KeyguardUpdateMonitor.getCurrentUser();
}
UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
List<UserInfo> profiles = userManager.getProfiles(currentUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 802cb831..97a9659 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -48,6 +48,7 @@
* A Task load queue
*/
class TaskResourceLoadQueue {
+
ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
/** Adds a new task to the load queue */
@@ -104,15 +105,18 @@
boolean mCancelled;
boolean mWaitingOnLoadQueue;
+ private final OnIdleChangedListener mOnIdleChangedListener;
+
/** Constructor, creates a new loading thread that loads task resources in the background */
public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
TaskKeyLruCache<Drawable> iconCache, Bitmap defaultThumbnail,
- BitmapDrawable defaultIcon) {
+ BitmapDrawable defaultIcon, OnIdleChangedListener onIdleChangedListener) {
mLoadQueue = loadQueue;
mIconCache = iconCache;
mDefaultThumbnail = defaultThumbnail;
mDefaultIcon = defaultIcon;
mMainThreadHandler = new Handler();
+ mOnIdleChangedListener = onIdleChangedListener;
mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
mLoadThread.start();
@@ -169,7 +173,11 @@
synchronized(mLoadQueue) {
try {
mWaitingOnLoadQueue = true;
+ mMainThreadHandler.post(
+ () -> mOnIdleChangedListener.onIdleChanged(true));
mLoadQueue.wait();
+ mMainThreadHandler.post(
+ () -> mOnIdleChangedListener.onIdleChanged(false));
mWaitingOnLoadQueue = false;
} catch (InterruptedException ie) {
ie.printStackTrace();
@@ -230,6 +238,10 @@
}
}
}
+
+ interface OnIdleChangedListener {
+ void onIdleChanged(boolean idle);
+ }
}
/**
@@ -298,15 +310,16 @@
// Initialize the proxy, cache and loaders
int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
+ mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
+ Looper.getMainLooper());
mLoadQueue = new TaskResourceLoadQueue();
mIconCache = new TaskKeyLruCache<>(iconCacheSize, mClearActivityInfoOnEviction);
mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction);
mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks,
mClearActivityInfoOnEviction);
mActivityInfoCache = new LruCache(numRecentTasks);
- mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultThumbnail, mDefaultIcon);
- mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
- Looper.getMainLooper());
+ mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultThumbnail, mDefaultIcon,
+ mHighResThumbnailLoader::setTaskLoadQueueIdle);
}
/** Returns the size of the app icon cache. */
@@ -360,9 +373,6 @@
mTempCache.evictAll();
if (!opts.onlyLoadForCache) {
mNumVisibleTasksLoaded = opts.numVisibleTasks;
-
- // Start the loader
- mLoader.start(context);
}
}
@@ -608,6 +618,13 @@
}
/**
+ * Starts loading tasks.
+ */
+ public void startLoader(Context ctx) {
+ mLoader.start(ctx);
+ }
+
+ /**
* Stops the task loader and clears all queued, pending task loads.
*/
private void stopLoader() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 8f24ec7..24a2927 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -1159,7 +1159,7 @@
*/
public int growsRecents() {
boolean result = mGrowRecents
- && mWindowManagerProxy.getDockSide() == WindowManager.DOCKED_TOP
+ && mDockSide == WindowManager.DOCKED_TOP
&& getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position;
if (result) {
return getSnapAlgorithm().getMiddleTarget().position;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index f6bd14c..9a3de61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -28,6 +28,7 @@
import android.support.v7.graphics.Palette;
import android.util.LayoutDirection;
+import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
import java.util.List;
@@ -120,7 +121,7 @@
paletteBuilder.addFilter(mBlackWhiteFilter);
palette = paletteBuilder.generate();
int foregroundColor;
- if (ColorUtils.calculateLuminance(backgroundColor) > 0.5) {
+ if (NotificationColorUtil.isColorLight(backgroundColor)) {
Palette.Swatch first = palette.getDarkVibrantSwatch();
Palette.Swatch second = palette.getVibrantSwatch();
if (first != null && second != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 1fd329c..8d9d461 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,16 +36,15 @@
import android.util.SparseArray;
import android.view.ContextThemeWrapper;
import android.view.Display;
-import android.view.IDockedStackListener.Stub;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.R;
@@ -336,8 +335,10 @@
mAccessibilityIcon = getDrawable(ctx, R.drawable.ic_sysbar_accessibility_button,
R.drawable.ic_sysbar_accessibility_button_dark);
- Context darkContext = new ContextThemeWrapper(ctx, R.style.DualToneDarkTheme);
- Context lightContext = new ContextThemeWrapper(ctx, R.style.DualToneLightTheme);
+ int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
+ int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
+ Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
+ Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
mImeIcon = getDrawable(darkContext, lightContext,
R.drawable.ic_ime_switcher_default, R.drawable.ic_ime_switcher_default);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
index 4d632af..f57b6b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
@@ -62,6 +62,7 @@
when(mMockSystemServicesProxy.getTaskThumbnail(anyInt(), anyBoolean()))
.thenReturn(mThumbnailData);
mLoader.setVisible(true);
+ mLoader.setTaskLoadQueueIdle(true);
}
@Test
@@ -75,6 +76,11 @@
assertFalse(mLoader.isLoading());
mLoader.setFlingingFast(false);
assertTrue(mLoader.isLoading());
+ mLoader.setFlingingFast(false);
+ mLoader.setTaskLoadQueueIdle(false);
+ assertFalse(mLoader.isLoading());
+ mLoader.setTaskLoadQueueIdle(true);
+ assertTrue(mLoader.isLoading());
}
@Test
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 41a78a7..93b5ed5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -172,7 +172,6 @@
startTrackingPackageChanges();
}
-
private void startTrackingPackageChanges() {
PackageMonitor monitor = new PackageMonitor() {
@Override
@@ -335,6 +334,7 @@
void listSessions(int userId, IResultReceiver receiver) {
Slog.i(TAG, "listSessions() for userId " + userId);
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
final Bundle resultData = new Bundle();
final ArrayList<String> sessions = new ArrayList<>();
@@ -364,6 +364,7 @@
void reset() {
Slog.i(TAG, "reset()");
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
synchronized (mLock) {
final int size = mServicesCache.size();
for (int i = 0; i < size; i++) {
@@ -376,6 +377,8 @@
// Called by Shell command.
void setLogLevel(int level) {
Slog.i(TAG, "setLogLevel(): " + level);
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
boolean debug = false;
boolean verbose = false;
if (level == AutofillManager.FLAG_ADD_CLIENT_VERBOSE) {
@@ -391,6 +394,8 @@
// Called by Shell command.
int getLogLevel() {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
synchronized (mLock) {
if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
if (sDebug) return AutofillManager.FLAG_ADD_CLIENT_DEBUG;
@@ -400,6 +405,8 @@
// Called by Shell command.
public int getMaxPartitions() {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
synchronized (mLock) {
return sPartitionMaxCount;
}
@@ -407,6 +414,7 @@
// Called by Shell command.
public void setMaxPartitions(int max) {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
Slog.i(TAG, "setMaxPartitions(): " + max);
synchronized (mLock) {
sPartitionMaxCount = max;
@@ -550,18 +558,39 @@
}
@Override
- public void updateSession(int sessionId, AutofillId id, Rect bounds,
+ public void updateSession(int sessionId, AutofillId autoFillId, Rect bounds,
AutofillValue value, int action, int flags, int userId) {
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
- service.updateSessionLocked(sessionId, getCallingUid(), id, bounds, value,
- action, flags);
+ service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, bounds,
+ value, action, flags);
}
}
}
@Override
+ public int updateOrRestartSession(IBinder activityToken, IBinder appCallback,
+ AutofillId autoFillId, Rect bounds, AutofillValue value, int userId,
+ boolean hasCallback, int flags, String packageName, int sessionId, int action) {
+ boolean restart = false;
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ restart = service.updateSessionLocked(sessionId, getCallingUid(), autoFillId,
+ bounds, value, action, flags);
+ }
+ }
+ if (restart) {
+ return startSession(activityToken, appCallback, autoFillId, bounds, value, userId,
+ hasCallback, flags, packageName);
+ }
+
+ // Nothing changed...
+ return sessionId;
+ }
+
+ @Override
public void finishSession(int sessionId, int userId) {
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 35371a7..2cb0bd5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.autofill;
+import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.NO_SESSION;
@@ -275,7 +276,7 @@
pruneAbandonedSessionsLocked();
final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
- hasCallback, flags, packageName);
+ hasCallback, packageName);
if (newSession == null) {
return NO_SESSION;
}
@@ -359,8 +360,7 @@
}
private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
- @NonNull IBinder appCallbackToken, boolean hasCallback, int flags,
- @NonNull String packageName) {
+ @NonNull IBinder appCallbackToken, boolean hasCallback, @NonNull String packageName) {
// use random ids so that one app cannot know that another app creates sessions
int sessionId;
int tries = 0;
@@ -402,18 +402,29 @@
}
}
- void updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
+ /**
+ * Updates a session and returns whether it should be restarted.
+ */
+ boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
AutofillValue value, int action, int flags) {
final Session session = mSessions.get(sessionId);
if (session == null || session.uid != uid) {
- if (sVerbose) {
- Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId + "(" + uid
- + ")");
+ if ((flags & FLAG_MANUAL_REQUEST) != 0) {
+ if (sDebug) {
+ Slog.d(TAG, "restarting session " + sessionId + " due to manual request on "
+ + autofillId);
+ }
+ return true;
}
- return;
+ if (sVerbose) {
+ Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId
+ + "(" + uid + ")");
+ }
+ return false;
}
session.updateLocked(autofillId, virtualBounds, value, action, flags);
+ return false;
}
void removeSessionLocked(int sessionId) {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 35f4fae..9aebf6d 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -404,10 +404,86 @@
}
private static abstract class PendingRequest implements Runnable {
- void cancel() {
+ protected final Object mLock = new Object();
+ private final WeakReference<RemoteFillService> mWeakService;
+ private final Runnable mTimeoutTrigger;
+ private final Handler mServiceHandler;
+
+ @GuardedBy("mLock")
+ private boolean mCancelled;
+
+ @GuardedBy("mLock")
+ private boolean mCompleted;
+
+ PendingRequest(RemoteFillService service) {
+ mWeakService = new WeakReference<>(service);
+ mServiceHandler = service.mHandler.getHandler();
+ mTimeoutTrigger = () -> {
+ synchronized (mLock) {
+ if (mCancelled) {
+ return;
+ }
+ mCompleted = true;
+ }
+
+ final RemoteFillService remoteService = mWeakService.get();
+ if (remoteService != null) {
+ fail(remoteService);
+ }
+ };
+ mServiceHandler.postAtTime(mTimeoutTrigger,
+ SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
}
+ protected RemoteFillService getService() {
+ return mWeakService.get();
+ }
+
+ /**
+ * Sub-classes must call this method when the remote service finishes, i.e., when it
+ * called {@code onFill...} or {@code onSave...}.
+ *
+ * @return {@code false} in the service is already finished, {@code true} otherwise.
+ */
+ protected final boolean finish() {
+ synchronized (mLock) {
+ if (mCompleted || mCancelled) {
+ return false;
+ }
+ mCompleted = true;
+ }
+ mServiceHandler.removeCallbacks(mTimeoutTrigger);
+ return true;
+ }
+
+ protected boolean isCancelledLocked() {
+ return mCancelled;
+ }
+
+ /**
+ * Cancels the service.
+ *
+ * @return {@code false} if service is already canceled, {@code true} otherwise.
+ */
+ boolean cancel() {
+ synchronized (mLock) {
+ if (mCancelled || mCompleted) {
+ return false;
+ }
+ mCancelled = true;
+ }
+
+ mServiceHandler.removeCallbacks(mTimeoutTrigger);
+ return true;
+ }
+
+ /**
+ * Called by the self-destructure timeout when the AutofilllService didn't reply to the
+ * request on time.
+ */
+ abstract void fail(RemoteFillService remoteService);
+
/**
* @return whether this request leads to a final state where no
* other requests can be made.
@@ -418,22 +494,14 @@
}
private static final class PendingFillRequest extends PendingRequest {
- private final Object mLock = new Object();
-
- private final WeakReference<RemoteFillService> mWeakService;
private final FillRequest mRequest;
private final IFillCallback mCallback;
private ICancellationSignal mCancellation;
- @GuardedBy("mLock")
- private boolean mCancelled;
-
- @GuardedBy("mLock")
- private boolean mCompleted;
-
public PendingFillRequest(FillRequest request, RemoteFillService service) {
+ super(service);
mRequest = request;
- mWeakService = new WeakReference<>(service);
+
mCallback = new IFillCallback.Stub() {
@Override
public void onCancellable(ICancellationSignal cancellation) {
@@ -441,7 +509,7 @@
final boolean cancelled;
synchronized (mLock) {
mCancellation = cancellation;
- cancelled = mCancelled;
+ cancelled = isCancelledLocked();
}
if (cancelled) {
try {
@@ -455,15 +523,10 @@
@Override
public void onSuccess(FillResponse response) {
- synchronized (mLock) {
- if (mCompleted) {
- return;
- }
- mCompleted = true;
- }
- RemoteFillService remoteService = mWeakService.get();
+ if (!finish()) return;
+
+ final RemoteFillService remoteService = getService();
if (remoteService != null) {
- service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
getCallingUid(), request.getFlags(), response);
}
@@ -471,132 +534,100 @@
@Override
public void onFailure(CharSequence message) {
- synchronized (mLock) {
- if (mCompleted) {
- return;
- }
- mCompleted = true;
- }
- RemoteFillService remoteService = mWeakService.get();
+ if (!finish()) return;
+
+ final RemoteFillService remoteService = getService();
if (remoteService != null) {
- service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
remoteService.dispatchOnFillRequestFailure(
PendingFillRequest.this, message);
}
}
};
- service.mHandler.getHandler().postAtTime(() -> {
- cancel();
- try {
- mCallback.onFailure(null);
- } catch (RemoteException e) {
- /* ignore */
- }
- }, PendingFillRequest.this,
- SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
+ }
+
+ @Override
+ void fail(RemoteFillService remoteService) {
+ remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
}
@Override
public void run() {
- RemoteFillService remoteService = mWeakService.get();
+ final RemoteFillService remoteService = getService();
if (remoteService != null) {
try {
remoteService.mAutoFillService.onFillRequest(mRequest, mCallback);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling on fill request", e);
- cancel();
+
+ remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
}
}
}
@Override
- public void cancel() {
- final ICancellationSignal cancellation;
- synchronized (mLock) {
- if (mCancelled) {
- return;
+ public boolean cancel() {
+ if (!super.cancel()) return false;
+
+ final ICancellationSignal cancellation = mCancellation;
+ if (cancellation != null) {
+ try {
+ cancellation.cancel();
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Error cancelling a fill request", e);
}
- mCancelled = true;
- cancellation = mCancellation;
}
- if (cancellation == null) {
- return;
- }
- try {
- cancellation.cancel();
- } catch (RemoteException e) {
- Slog.e(LOG_TAG, "Error cancelling a fill request", e);
- }
+ return true;
}
}
private static final class PendingSaveRequest extends PendingRequest {
- private final Object mLock = new Object();
-
- private final WeakReference<RemoteFillService> mWeakService;
private final SaveRequest mRequest;
private final ISaveCallback mCallback;
- @GuardedBy("mLock")
- private boolean mCompleted;
-
public PendingSaveRequest(@NonNull SaveRequest request,
@NonNull RemoteFillService service) {
+ super(service);
mRequest = request;
- mWeakService = new WeakReference<>(service);
+
mCallback = new ISaveCallback.Stub() {
@Override
public void onSuccess() {
- synchronized (mLock) {
- if (mCompleted) {
- return;
- }
- mCompleted = true;
- }
- cancel();
- RemoteFillService service = mWeakService.get();
- if (service != null) {
- service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
- service.dispatchOnSaveRequestSuccess(
- PendingSaveRequest.this);
+ if (!finish()) return;
+
+ final RemoteFillService remoteService = getService();
+ if (remoteService != null) {
+ remoteService.dispatchOnSaveRequestSuccess(PendingSaveRequest.this);
}
}
@Override
public void onFailure(CharSequence message) {
- synchronized (mLock) {
- if (mCompleted) {
- return;
- }
- mCompleted = true;
- }
- RemoteFillService service = mWeakService.get();
- if (service != null) {
- service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
- service.dispatchOnSaveRequestFailure(
- PendingSaveRequest.this, message);
+ if (!finish()) return;
+
+ final RemoteFillService remoteService = getService();
+ if (remoteService != null) {
+ remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this,
+ message);
}
}
};
- service.mHandler.getHandler().postAtTime(() -> {
- cancel();
- try {
- mCallback.onFailure(null);
- } catch (RemoteException e) {
- /* ignore */
- }
- }, PendingSaveRequest.this,
- SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
+ }
+
+ @Override
+ void fail(RemoteFillService remoteService) {
+ remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
}
@Override
public void run() {
- final RemoteFillService service = mWeakService.get();
- if (service != null) {
+ final RemoteFillService remoteService = getService();
+ if (remoteService != null) {
try {
- service.mAutoFillService.onSaveRequest(mRequest, mCallback);
+ remoteService.mAutoFillService.onSaveRequest(mRequest, mCallback);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling on save request", e);
+
+ remoteService.dispatchOnFillRequestFailure(PendingSaveRequest.this, null);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 6d58e72..0122301 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -818,6 +818,7 @@
}
}
if (atLeastOneChanged) {
+ if (sDebug) Slog.d(TAG, "at least one field changed - showing save UI");
mService.setSaveShown();
getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName,
this);
@@ -887,7 +888,7 @@
if (sVerbose) {
Slog.v(TAG, "Dumping structure of " + context + " before calling service.save()");
- context.getStructure().dump();
+ context.getStructure().dump(false);
}
}
@@ -1401,7 +1402,7 @@
pw.println(context.getStructure() + " (look at logcat)");
// TODO: add method on AssistStructure to dump on pw
- context.getStructure().dump();
+ context.getStructure().dump(false);
}
}
} else {
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 4f69f64..c3d55054 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -16,6 +16,7 @@
package com.android.server.autofill.ui;
import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -108,6 +109,8 @@
* Displays an error message to the user.
*/
public void showError(@Nullable CharSequence message, @NonNull AutoFillUiCallback callback) {
+ Slog.w(TAG, "showError(): " + message);
+
mHandler.post(() -> {
if (mCallback != callback) {
return;
@@ -237,6 +240,7 @@
*/
public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info,
@NonNull String packageName, @NonNull AutoFillUiCallback callback) {
+ if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info);
int numIds = 0;
numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 3f8d508..30de4ba 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -790,6 +790,11 @@
return false;
}
+ // 4. it is an "instant" app
+ if (app.isInstantApp()) {
+ return false;
+ }
+
// Everything else checks out; the only remaining roadblock would be if the
// package were disabled
return !appIsDisabled(app, pm);
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 04421cc..6b5366a 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -640,7 +640,7 @@
int result = ActivityManager.getService().startActivityWithConfig(
null, null, homeIntent, null, null, null, 0, 0,
mConfiguration, null, UserHandle.USER_CURRENT);
- if (result >= ActivityManager.START_SUCCESS) {
+ if (ActivityManager.isStartResultSuccessful(result)) {
dockAppStarted = true;
} else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
Slog.e(TAG, "Could not start dock app: " + homeIntent
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e585f7b..df32089 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5391,8 +5391,9 @@
boolean doLowMem = app.instr == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
- Slog.i(TAG, "Process " + app.processName + " (pid " + pid
- + ") has died");
+ Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: "
+ + ProcessList.makeOomAdjString(app.setAdj)
+ + ProcessList.makeProcStateString(app.setProcState));
mAllowLowerMemLevel = true;
} else {
// Note that we always want to do oom adj to update our state with the
@@ -5400,7 +5401,8 @@
mAllowLowerMemLevel = false;
doLowMem = false;
}
- EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
+ EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName,
+ app.setAdj, app.setProcState);
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
handleAppDiedLocked(app, false, true);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 6d4eb5b..a2eec5c 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -544,7 +544,7 @@
ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
ActivityStack targetStack) {
- if (result < START_SUCCESS) {
+ if (ActivityManager.isStartResultFatalError(result)) {
return;
}
@@ -956,7 +956,8 @@
// If we are not able to proceed, disassociate the activity from the task. Leaving an
// activity in an incomplete state can lead to issues, such as performing operations
// without a window container.
- if (result < START_SUCCESS && mStartActivity.getTask() != null) {
+ if (ActivityManager.isStartResultFatalError(result)
+ && mStartActivity.getTask() != null) {
mStartActivity.getTask().removeActivity(mStartActivity);
}
mService.mWindowManager.continueSurfaceLayout();
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 372ab6b..b2d3137 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -34,7 +34,7 @@
# Application process bound to work
30010 am_proc_bound (User|1|5),(PID|1|5),(Process Name|3)
# Application process died
-30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3)
+30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(ProcState|1|5)
# The Activity Manager failed to pause the given activity.
30012 am_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
# Attempting to pause the current activity
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index fe49813..4fc6ddd 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -34,8 +34,13 @@
public abstract class AuthenticationClient extends ClientMonitor {
private long mOpId;
- public abstract boolean handleFailedAttempt();
+ public abstract int handleFailedAttempt();
public abstract void resetFailedAttempts();
+
+ public static final int LOCKOUT_NONE = 0;
+ public static final int LOCKOUT_TIMED = 1;
+ public static final int LOCKOUT_PERMANENT = 2;
+
private boolean mAlreadyCancelled;
public AuthenticationClient(Context context, long halDeviceId, IBinder token,
@@ -79,19 +84,21 @@
FingerprintUtils.vibrateFingerprintError(getContext());
}
// allow system-defined limit of number of attempts before giving up
- boolean inLockoutMode = handleFailedAttempt();
- // send lockout event in case driver doesn't enforce it.
- if (inLockoutMode) {
+ int lockoutMode = handleFailedAttempt();
+ if (lockoutMode != LOCKOUT_NONE) {
try {
- Slog.w(TAG, "Forcing lockout (fp driver code should do this!)");
- stop(false); // cancel fingerprint authentication
- receiver.onError(getHalDeviceId(),
- FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */);
+ Slog.w(TAG, "Forcing lockout (fp driver code should do this!), mode(" +
+ lockoutMode + ")");
+ stop(false);
+ int errorCode = lockoutMode == LOCKOUT_TIMED ?
+ FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
+ FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+ receiver.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to notify lockout:", e);
}
}
- result |= inLockoutMode;
+ result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode
} else {
if (receiver != null) {
FingerprintUtils.vibrateFingerprintSuccess(getContext());
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 6f5b028..6cc7071 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -108,6 +108,7 @@
int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image
// acquisition in some cases (too fast, too slow, dirty sensor, etc.)
int lockout; // total number of lockouts
+ int permanentLockout; // total number of permanent lockouts
}
private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
@@ -118,13 +119,16 @@
Collections.synchronizedMap(new HashMap<>());
private final AppOpsManager mAppOps;
private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
- private static final int MAX_FAILED_ATTEMPTS = 5;
+ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
+ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
+
private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
private final String mKeyguardPackage;
private int mCurrentUserId = UserHandle.USER_NULL;
private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
private Context mContext;
private long mHalDeviceId;
+ private boolean mTimedLockoutCleared;
private int mFailedAttempts;
@GuardedBy("this")
private IBiometricsFingerprint mDaemon;
@@ -173,7 +177,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
- resetFailedAttempts();
+ resetFailedAttempts(false /* clearAttemptCounter */);
}
}
};
@@ -181,7 +185,7 @@
private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
@Override
public void run() {
- resetFailedAttempts();
+ resetFailedAttempts(true /* clearAttemptCounter */);
}
};
@@ -369,6 +373,7 @@
if (client != null && client.onError(error, vendorCode)) {
removeClient(client);
}
+
if (DEBUG) Slog.v(TAG, "handleError(client="
+ (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
// This is the magic code that starts the next client when the old client finishes.
@@ -438,7 +443,7 @@
if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
removeClient(client);
}
- if (mPerformanceStats != null && !inLockoutMode()
+ if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
&& client instanceof AuthenticationClient) {
// ignore enrollment acquisitions or acquisitions when we're locked out
mPerformanceStats.acquire++;
@@ -482,8 +487,14 @@
}
}
- private boolean inLockoutMode() {
- return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
+ private int getLockoutMode() {
+ if (mFailedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
+ return AuthenticationClient.LOCKOUT_PERMANENT;
+ } else if (mFailedAttempts > 0 && mTimedLockoutCleared == false &&
+ (mFailedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
+ return AuthenticationClient.LOCKOUT_TIMED;
+ }
+ return AuthenticationClient.LOCKOUT_NONE;
}
private void scheduleLockoutReset() {
@@ -801,22 +812,27 @@
AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) {
@Override
- public boolean handleFailedAttempt() {
+ public int handleFailedAttempt() {
mFailedAttempts++;
- if (mFailedAttempts == MAX_FAILED_ATTEMPTS) {
+ mTimedLockoutCleared = false;
+ final int lockoutMode = getLockoutMode();
+ if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
+ mPerformanceStats.permanentLockout++;
+ } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
mPerformanceStats.lockout++;
}
- if (inLockoutMode()) {
- // Failing multiple times will continue to push out the lockout time.
+
+ // Failing multiple times will continue to push out the lockout time
+ if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
scheduleLockoutReset();
- return true;
+ return lockoutMode;
}
- return false;
+ return AuthenticationClient.LOCKOUT_NONE;
}
@Override
public void resetFailedAttempts() {
- FingerprintService.this.resetFailedAttempts();
+ FingerprintService.this.resetFailedAttempts(true /* clearAttemptCounter */);
}
@Override
@@ -830,11 +846,15 @@
}
};
- if (inLockoutMode()) {
- Slog.v(TAG, "In lockout mode; disallowing authentication");
- // Don't bother starting the client. Just send the error message.
- if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */)) {
- Slog.w(TAG, "Cannot send timeout message to client");
+ int lockoutMode = getLockoutMode();
+ if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
+ Slog.v(TAG, "In lockout mode(" + lockoutMode +
+ ") ; disallowing authentication");
+ int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
+ FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
+ FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+ if (!client.onError(errorCode, 0 /* vendorCode */)) {
+ Slog.w(TAG, "Cannot send permanent lockout message to client");
}
return;
}
@@ -864,11 +884,16 @@
startClient(client, true /* initiatedByClient */);
}
- protected void resetFailedAttempts() {
- if (DEBUG && inLockoutMode()) {
- Slog.v(TAG, "Reset fingerprint lockout");
+ // attempt counter should only be cleared when Keyguard goes away or when
+ // a fingerprint is successfully authenticated
+ protected void resetFailedAttempts(boolean clearAttemptCounter) {
+ if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
+ Slog.v(TAG, "Reset fingerprint lockout, clearAttemptCounter=" + clearAttemptCounter);
}
- mFailedAttempts = 0;
+ if (clearAttemptCounter) {
+ mFailedAttempts = 0;
+ }
+ mTimedLockoutCleared = true;
// If we're asked to reset failed attempts externally (i.e. from Keyguard),
// the alarm might still be pending; remove it.
cancelLockoutReset();
@@ -1301,6 +1326,7 @@
set.put("reject", (stats != null) ? stats.reject : 0);
set.put("acquire", (stats != null) ? stats.acquire : 0);
set.put("lockout", (stats != null) ? stats.lockout : 0);
+ set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
// cryptoStats measures statistics about secure fingerprint transactions
// (e.g. to unlock password storage, make secure purchases, etc.)
set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
@@ -1336,6 +1362,7 @@
proto.write(FingerprintActionStatsProto.REJECT, normal.reject);
proto.write(FingerprintActionStatsProto.ACQUIRE, normal.acquire);
proto.write(FingerprintActionStatsProto.LOCKOUT, normal.lockout);
+ proto.write(FingerprintActionStatsProto.LOCKOUT_PERMANENT, normal.lockout);
proto.end(countsToken);
}
@@ -1348,6 +1375,7 @@
proto.write(FingerprintActionStatsProto.REJECT, crypto.reject);
proto.write(FingerprintActionStatsProto.ACQUIRE, crypto.acquire);
proto.write(FingerprintActionStatsProto.LOCKOUT, crypto.lockout);
+ proto.write(FingerprintActionStatsProto.LOCKOUT_PERMANENT, crypto.lockout);
proto.end(countsToken);
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index e2c1274..c08f866 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -218,6 +218,11 @@
private static final String KEY_BG_MODERATE_JOB_COUNT = "bg_moderate_job_count";
private static final String KEY_BG_LOW_JOB_COUNT = "bg_low_job_count";
private static final String KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count";
+ private static final String KEY_MAX_STANDARD_RESCHEDULE_COUNT
+ = "max_standard_reschedule_count";
+ private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count";
+ private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time";
+ private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time";
private static final int DEFAULT_MIN_IDLE_COUNT = 1;
private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -233,6 +238,10 @@
private static final int DEFAULT_BG_MODERATE_JOB_COUNT = 4;
private static final int DEFAULT_BG_LOW_JOB_COUNT = 1;
private static final int DEFAULT_BG_CRITICAL_JOB_COUNT = 1;
+ private static final int DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT = Integer.MAX_VALUE;
+ private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE;
+ private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
+ private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
/**
* Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -303,6 +312,24 @@
* memory state.
*/
int BG_CRITICAL_JOB_COUNT = DEFAULT_BG_CRITICAL_JOB_COUNT;
+ /**
+ * The maximum number of times we allow a job to have itself rescheduled before
+ * giving up on it, for standard jobs.
+ */
+ int MAX_STANDARD_RESCHEDULE_COUNT = DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT;
+ /**
+ * The maximum number of times we allow a job to have itself rescheduled before
+ * giving up on it, for jobs that are executing work.
+ */
+ int MAX_WORK_RESCHEDULE_COUNT = DEFAULT_MAX_WORK_RESCHEDULE_COUNT;
+ /**
+ * The minimum backoff time to allow for linear backoff.
+ */
+ long MIN_LINEAR_BACKOFF_TIME = DEFAULT_MIN_LINEAR_BACKOFF_TIME;
+ /**
+ * The minimum backoff time to allow for exponential backoff.
+ */
+ long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -374,6 +401,14 @@
if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
}
+ MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
+ DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
+ MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT,
+ DEFAULT_MAX_WORK_RESCHEDULE_COUNT);
+ MIN_LINEAR_BACKOFF_TIME = mParser.getLong(KEY_MIN_LINEAR_BACKOFF_TIME,
+ DEFAULT_MIN_LINEAR_BACKOFF_TIME);
+ MIN_EXP_BACKOFF_TIME = mParser.getLong(KEY_MIN_EXP_BACKOFF_TIME,
+ DEFAULT_MIN_EXP_BACKOFF_TIME);
}
}
@@ -421,11 +456,38 @@
pw.print(" "); pw.print(KEY_BG_CRITICAL_JOB_COUNT); pw.print("=");
pw.print(BG_CRITICAL_JOB_COUNT); pw.println();
+
+ pw.print(" "); pw.print(KEY_MAX_STANDARD_RESCHEDULE_COUNT); pw.print("=");
+ pw.print(MAX_STANDARD_RESCHEDULE_COUNT); pw.println();
+
+ pw.print(" "); pw.print(KEY_MAX_WORK_RESCHEDULE_COUNT); pw.print("=");
+ pw.print(MAX_WORK_RESCHEDULE_COUNT); pw.println();
+
+ pw.print(" "); pw.print(KEY_MIN_LINEAR_BACKOFF_TIME); pw.print("=");
+ pw.print(MIN_LINEAR_BACKOFF_TIME); pw.println();
+
+ pw.print(" "); pw.print(KEY_MIN_EXP_BACKOFF_TIME); pw.print("=");
+ pw.print(MIN_EXP_BACKOFF_TIME); pw.println();
}
}
final Constants mConstants;
+ static final Comparator<JobStatus> mEnqueueTimeComparator = (o1, o2) -> {
+ if (o1.enqueueTime < o2.enqueueTime) {
+ return -1;
+ }
+ return o1.enqueueTime > o2.enqueueTime ? 1 : 0;
+ };
+
+ static <T> void addOrderedItem(ArrayList<T> array, T newItem, Comparator<T> comparator) {
+ int where = Collections.binarySearch(array, newItem, comparator);
+ if (where < 0) {
+ where = ~where;
+ }
+ array.add(where, newItem);
+ }
+
/**
* Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
* still clean up. On reinstall the package will have a new uid.
@@ -647,7 +709,7 @@
// This is a new job, we can just immediately put it on the pending
// list and try to run it.
mJobPackageTracker.notePending(jobStatus);
- mPendingJobs.add(jobStatus);
+ addOrderedItem(mPendingJobs, jobStatus, mEnqueueTimeComparator);
maybeRunPendingJobsLocked();
}
}
@@ -771,7 +833,7 @@
// except those using the idle exemption flag.
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJob();
+ final JobStatus executing = jsc.getRunningJobLocked();
if (executing != null
&& (executing.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0) {
jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE);
@@ -798,7 +860,7 @@
if (mPendingJobs.size() <= 0) {
for (int i=0; i<mActiveServices.size(); i++) {
final JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus job = jsc.getRunningJob();
+ final JobStatus job = jsc.getRunningJobLocked();
if (job != null
&& (job.getJob().getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0
&& !job.dozeWhitelisted) {
@@ -918,6 +980,7 @@
if (!jobStatus.isPreparedLocked()) {
Slog.wtf(TAG, "Not yet prepared when started tracking: " + jobStatus);
}
+ jobStatus.enqueueTime = SystemClock.elapsedRealtime();
final boolean update = mJobs.add(jobStatus);
if (mReadyToRock) {
for (int i = 0; i < mControllers.size(); i++) {
@@ -953,7 +1016,7 @@
private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJob();
+ final JobStatus executing = jsc.getRunningJobLocked();
if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
jsc.cancelExecutingJobLocked(reason);
return true;
@@ -970,11 +1033,7 @@
private boolean isCurrentlyActiveLocked(JobStatus job) {
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext serviceContext = mActiveServices.get(i);
- // The 'unsafe' direct-internal-reference running-job inspector is okay to
- // use here because we are already holding the necessary lock *and* we
- // immediately discard the returned object reference, if any; we return
- // only a boolean state indicator to the caller.
- final JobStatus running = serviceContext.getRunningJobUnsafeLocked();
+ final JobStatus running = serviceContext.getRunningJobLocked();
if (running != null && running.matches(job.getUid(), job.getJobId())) {
return true;
}
@@ -1016,18 +1075,38 @@
final int backoffAttempts = failureToReschedule.getNumFailures() + 1;
long delayMillis;
+ if (failureToReschedule.hasWorkLocked()) {
+ if (backoffAttempts > mConstants.MAX_WORK_RESCHEDULE_COUNT) {
+ Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
+ + backoffAttempts + " > work limit "
+ + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
+ return null;
+ }
+ } else if (backoffAttempts > mConstants.MAX_STANDARD_RESCHEDULE_COUNT) {
+ Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
+ + backoffAttempts + " > std limit " + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
+ return null;
+ }
+
switch (job.getBackoffPolicy()) {
- case JobInfo.BACKOFF_POLICY_LINEAR:
- delayMillis = initialBackoffMillis * backoffAttempts;
- break;
+ case JobInfo.BACKOFF_POLICY_LINEAR: {
+ long backoff = initialBackoffMillis;
+ if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME) {
+ backoff = mConstants.MIN_LINEAR_BACKOFF_TIME;
+ }
+ delayMillis = backoff * backoffAttempts;
+ } break;
default:
if (DEBUG) {
Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
}
- case JobInfo.BACKOFF_POLICY_EXPONENTIAL:
- delayMillis =
- (long) Math.scalb(initialBackoffMillis, backoffAttempts - 1);
- break;
+ case JobInfo.BACKOFF_POLICY_EXPONENTIAL: {
+ long backoff = initialBackoffMillis;
+ if (backoff < mConstants.MIN_EXP_BACKOFF_TIME) {
+ backoff = mConstants.MIN_EXP_BACKOFF_TIME;
+ }
+ delayMillis = (long) Math.scalb(backoff, backoffAttempts - 1);
+ } break;
}
delayMillis =
Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
@@ -1163,7 +1242,7 @@
// state is such that all ready jobs should be run immediately.
if (runNow != null && isReadyToBeExecutedLocked(runNow)) {
mJobPackageTracker.notePending(runNow);
- mPendingJobs.add(runNow);
+ addOrderedItem(mPendingJobs, runNow, mEnqueueTimeComparator);
} else {
queueReadyJobsForExecutionLocked();
}
@@ -1237,6 +1316,9 @@
if (newReadyJobs != null) {
noteJobsPending(newReadyJobs);
mPendingJobs.addAll(newReadyJobs);
+ if (mPendingJobs.size() > 1) {
+ mPendingJobs.sort(mEnqueueTimeComparator);
+ }
}
newReadyJobs = null;
}
@@ -1326,6 +1408,9 @@
}
noteJobsPending(runnableJobs);
mPendingJobs.addAll(runnableJobs);
+ if (mPendingJobs.size() > 1) {
+ mPendingJobs.sort(mEnqueueTimeComparator);
+ }
} else {
if (DEBUG) {
Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: Not running anything.");
@@ -1515,7 +1600,7 @@
int numForeground = 0;
for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
final JobServiceContext js = mActiveServices.get(i);
- final JobStatus status = js.getRunningJob();
+ final JobStatus status = js.getRunningJobLocked();
if ((contextIdToJobMap[i] = status) != null) {
numActive++;
if (status.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
@@ -1591,10 +1676,10 @@
for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
boolean preservePreferredUid = false;
if (act[i]) {
- JobStatus js = mActiveServices.get(i).getRunningJob();
+ JobStatus js = mActiveServices.get(i).getRunningJobLocked();
if (js != null) {
if (DEBUG) {
- Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJob());
+ Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJobLocked());
}
// preferredUid will be set to uid of currently running job.
mActiveServices.get(i).preemptExecutingJobLocked();
@@ -2099,7 +2184,7 @@
continue;
}
- job.dump(pw, " ", true);
+ job.dump(pw, " ", true, now);
pw.print(" Ready: ");
pw.print(isReadyToBeExecutedLocked(job));
pw.print(" (job=");
@@ -2169,22 +2254,22 @@
JobStatus job = mPendingJobs.get(i);
pw.print(" Pending #"); pw.print(i); pw.print(": ");
pw.println(job.toShortString());
- job.dump(pw, " ", false);
+ job.dump(pw, " ", false, now);
int priority = evaluateJobPriorityLocked(job);
if (priority != JobInfo.PRIORITY_DEFAULT) {
pw.print(" Evaluated priority: "); pw.println(priority);
}
pw.print(" Tag: "); pw.println(job.getTag());
pw.print(" Enq: ");
- TimeUtils.formatDuration(now - job.madePending, pw);
- pw.println(" ago");
+ TimeUtils.formatDuration(job.madePending - now, pw);
+ pw.println();
}
pw.println();
pw.println("Active jobs:");
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext jsc = mActiveServices.get(i);
pw.print(" Slot #"); pw.print(i); pw.print(": ");
- final JobStatus job = jsc.getRunningJob();
+ final JobStatus job = jsc.getRunningJobLocked();
if (job == null) {
pw.println("inactive");
continue;
@@ -2195,13 +2280,14 @@
pw.print(", timeout at: ");
TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw);
pw.println();
- job.dump(pw, " ", false);
- int priority = evaluateJobPriorityLocked(jsc.getRunningJob());
+ job.dump(pw, " ", false, now);
+ int priority = evaluateJobPriorityLocked(jsc.getRunningJobLocked());
if (priority != JobInfo.PRIORITY_DEFAULT) {
pw.print(" Evaluated priority: "); pw.println(priority);
}
- pw.print(" Active at "); pw.println(job.madeActive);
- pw.print(" Pending for ");
+ pw.print(" Active at ");
+ TimeUtils.formatDuration(job.madeActive - now, pw);
+ pw.print(", pending for ");
TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
pw.println();
}
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index bdcf642..ff39baf 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -146,7 +146,7 @@
}
/**
- * Give a job to this context for execution. Callers must first check {@link #getRunningJob()}
+ * Give a job to this context for execution. Callers must first check {@link #getRunningJobLocked()}
* and ensure it is null to make sure this is a valid context.
* @param job The status of the job that we are going to run.
* @return True if the job is valid and is running. False if the job cannot be executed.
@@ -210,23 +210,8 @@
/**
* Used externally to query the running job. Will return null if there is no job running.
- * Be careful when using this function, at any moment it's possible that the job returned may
- * stop executing.
*/
- JobStatus getRunningJob() {
- final JobStatus job;
- synchronized (mLock) {
- job = mRunningJob;
- }
- return job == null ? null : new JobStatus(job);
- }
-
- /**
- * Internal non-cloning inspection of the currently running job, if any. The lock
- * must be held when calling this *and* for the entire lifetime of using its returned
- * JobStatus object!
- */
- JobStatus getRunningJobUnsafeLocked() {
+ JobStatus getRunningJobLocked() {
return mRunningJob;
}
@@ -256,7 +241,7 @@
}
boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId) {
- final JobStatus executing = getRunningJob();
+ final JobStatus executing = getRunningJobLocked();
if (executing != null && (userId == UserHandle.USER_ALL || userId == executing.getUserId())
&& (pkgName == null || pkgName.equals(executing.getSourcePackageName()))
&& (!matchJobId || jobId == executing.getJobId())) {
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 57b1ccc..497d36f 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -454,10 +454,12 @@
synchronized (mLock) {
jobs = readJobMapImpl(fis);
if (jobs != null) {
+ long now = SystemClock.elapsedRealtime();
IActivityManager am = ActivityManager.getService();
for (int i=0; i<jobs.size(); i++) {
JobStatus js = jobs.get(i);
js.prepareLocked(am);
+ js.enqueueTime = now;
this.jobSet.add(js);
}
}
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 4d507d6..53bf402 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -22,14 +22,10 @@
import android.app.job.JobWorkItem;
import android.content.ClipData;
import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.Intent;
import android.net.Uri;
-import android.os.Binder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
@@ -180,7 +176,10 @@
// Used by shell commands
public int overrideState = 0;
- // Metrics about queue latency
+ // When this job was enqueued, for ordering. (in elapsedRealtimeMillis)
+ public long enqueueTime;
+
+ // Metrics about queue latency. (in uptimeMillis)
public long madePending;
public long madeActive;
@@ -349,6 +348,10 @@
return null;
}
+ public boolean hasWorkLocked() {
+ return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked();
+ }
+
public boolean hasExecutingWorkLocked() {
return executingWork != null && executingWork.size() > 0;
}
@@ -744,10 +747,11 @@
sb.append(getSourceUid());
if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
|| latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
+ long now = SystemClock.elapsedRealtime();
sb.append(" TIME=");
- sb.append(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
- sb.append("-");
- sb.append(formatRunTime(latestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
+ formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
+ sb.append(":");
+ formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
}
if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
sb.append(" NET=");
@@ -789,17 +793,19 @@
return sb.toString();
}
- private String formatRunTime(long runtime, long defaultValue) {
+ private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) {
if (runtime == defaultValue) {
- return "none";
+ pw.print("none");
} else {
- long elapsedNow = SystemClock.elapsedRealtime();
- long nextRuntime = runtime - elapsedNow;
- if (nextRuntime > 0) {
- return DateUtils.formatElapsedTime(nextRuntime / 1000);
- } else {
- return "-" + DateUtils.formatElapsedTime(nextRuntime / -1000);
- }
+ TimeUtils.formatDuration(runtime - now, pw);
+ }
+ }
+
+ private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) {
+ if (runtime == defaultValue) {
+ sb.append("none");
+ } else {
+ TimeUtils.formatDuration(runtime - now, sb);
}
}
@@ -881,7 +887,7 @@
}
// Dumpsys infrastructure
- public void dump(PrintWriter pw, String prefix, boolean full) {
+ public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
pw.print(prefix); UserHandle.formatUid(pw, callingUid);
pw.print(" tag="); pw.println(tag);
pw.print(prefix);
@@ -1020,10 +1026,14 @@
dumpJobWorkItem(pw, prefix, executingWork.get(i), i);
}
}
- pw.print(prefix); pw.print("Earliest run time: ");
- pw.println(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
- pw.print(prefix); pw.print("Latest run time: ");
- pw.println(formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME));
+ pw.print(prefix); pw.print("Enqueue time: ");
+ TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
+ pw.println();
+ pw.print(prefix); pw.print("Run time: earliest=");
+ formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
+ pw.print(", latest=");
+ formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
+ pw.println();
if (numFailures != 0) {
pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 0e1f485..ef3e7bc 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -20,6 +20,7 @@
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
@@ -46,6 +47,7 @@
import android.os.ShellCallback;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -243,11 +245,14 @@
packageFilter, null, null);
final IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(ACTION_USER_ADDED);
userFilter.addAction(ACTION_USER_REMOVED);
getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
userFilter, null, null);
restoreSettings();
+
+ initIfNeeded();
onSwitchUser(UserHandle.USER_SYSTEM);
publishBinderService(Context.OVERLAY_SERVICE, mService);
@@ -269,14 +274,31 @@
}
}
+ private void initIfNeeded() {
+ final UserManager um = getContext().getSystemService(UserManager.class);
+ final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
+ synchronized (mLock) {
+ final int userCount = users.size();
+ for (int i = 0; i < userCount; i++) {
+ final UserInfo userInfo = users.get(i);
+ if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
+ // Initialize any users that can't be switched to, as there state would
+ // never be setup in onSwitchUser(). We will switch to the system user right
+ // after this, and its state will be setup there.
+ final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
+ updateOverlayPaths(users.get(i).id, targets);
+ }
+ }
+ }
+ }
+
@Override
public void onSwitchUser(final int newUserId) {
// ensure overlays in the settings are up-to-date, and propagate
// any asset changes to the rest of the system
- final List<String> targets;
synchronized (mLock) {
- targets = mImpl.onSwitchUser(newUserId);
- updateAssetsLocked(newUserId, targets);
+ final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
+ updateAssets(newUserId, targets);
}
schedulePersistSettings();
}
@@ -428,10 +450,19 @@
private final class UserReceiver extends BroadcastReceiver {
@Override
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
switch (intent.getAction()) {
+ case ACTION_USER_ADDED:
+ if (userId != UserHandle.USER_NULL) {
+ final ArrayList<String> targets;
+ synchronized (mLock) {
+ targets = mImpl.updateOverlaysForUser(userId);
+ }
+ updateOverlayPaths(userId, targets);
+ }
+ break;
+
case ACTION_USER_REMOVED:
- final int userId =
- intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
if (userId != UserHandle.USER_NULL) {
synchronized (mLock) {
mImpl.onUserRemoved(userId);
@@ -647,9 +678,7 @@
public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
schedulePersistSettings();
FgThread.getHandler().post(() -> {
- synchronized (mLock) {
- updateAssetsLocked(userId, targetPackageName);
- }
+ updateAssets(userId, targetPackageName);
final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", targetPackageName, null));
@@ -670,13 +699,10 @@
}
}
- private void updateAssetsLocked(final int userId, final String targetPackageName) {
- final List<String> list = new ArrayList<>();
- list.add(targetPackageName);
- updateAssetsLocked(userId, list);
- }
-
- private void updateAssetsLocked(final int userId, List<String> targetPackageNames) {
+ /**
+ * Updates the target packages' set of enabled overlays in PackageManager.
+ */
+ private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
if (DEBUG) {
Slog.d(TAG, "Updating overlay assets");
}
@@ -706,12 +732,19 @@
}
if (!pm.setEnabledOverlayPackages(
- userId, targetPackageName, pendingChanges.get(targetPackageName))) {
+ userId, targetPackageName, pendingChanges.get(targetPackageName))) {
Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
- targetPackageName, userId));
+ targetPackageName, userId));
}
}
+ }
+ private void updateAssets(final int userId, final String targetPackageName) {
+ updateAssets(userId, Collections.singletonList(targetPackageName));
+ }
+
+ private void updateAssets(final int userId, List<String> targetPackageNames) {
+ updateOverlayPaths(userId, targetPackageNames);
final IActivityManager am = ActivityManager.getService();
try {
am.scheduleApplicationInfoChanged(targetPackageNames, userId);
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 5196c66..261bcc5 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -68,15 +68,15 @@
mListener = listener;
}
- /*
- * Call this when switching to a new Android user. Will return a list of
- * target packages that must refresh their overlays. This list is the union
+ /**
+ * Call this to synchronize the Settings for a user with what PackageManager knows about a user.
+ * Returns a list of target packages that must refresh their overlays. This list is the union
* of two sets: the set of targets with currently active overlays, and the
* set of targets that had, but no longer have, active overlays.
*/
- List<String> onSwitchUser(final int newUserId) {
+ ArrayList<String> updateOverlaysForUser(final int newUserId) {
if (DEBUG) {
- Slog.d(TAG, "onSwitchUser newUserId=" + newUserId);
+ Slog.d(TAG, "updateOverlaysForUser newUserId=" + newUserId);
}
final Set<String> packagesToUpdateAssets = new ArraySet<>();
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 2f83793..353b710 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -22,12 +22,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.om.OverlayInfo;
+import android.os.UserHandle;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -266,32 +268,32 @@
return true;
}
- private static final String TAB1 = " ";
- private static final String TAB2 = TAB1 + TAB1;
- private static final String TAB3 = TAB2 + TAB1;
-
- void dump(@NonNull final PrintWriter pw) {
+ void dump(@NonNull final PrintWriter p) {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(p, " ");
pw.println("Settings");
- pw.println(TAB1 + "Items");
+ pw.increaseIndent();
if (mItems.isEmpty()) {
- pw.println(TAB2 + "<none>");
+ pw.println("<none>");
return;
}
final int N = mItems.size();
for (int i = 0; i < N; i++) {
final SettingsItem item = mItems.get(i);
- final StringBuilder sb = new StringBuilder();
- sb.append(TAB2 + item.mPackageName + ":" + item.getUserId() + " {\n");
- sb.append(TAB3 + "mPackageName.......: " + item.mPackageName + "\n");
- sb.append(TAB3 + "mUserId............: " + item.getUserId() + "\n");
- sb.append(TAB3 + "mTargetPackageName.: " + item.getTargetPackageName() + "\n");
- sb.append(TAB3 + "mBaseCodePath......: " + item.getBaseCodePath() + "\n");
- sb.append(TAB3 + "mState.............: " + OverlayInfo.stateToString(item.getState()) + "\n");
- sb.append(TAB3 + "mIsEnabled.........: " + item.isEnabled() + "\n");
- sb.append(TAB2 + "}");
- pw.println(sb.toString());
+ pw.println(item.mPackageName + ":" + item.getUserId() + " {");
+ pw.increaseIndent();
+
+ pw.print("mPackageName.......: "); pw.println(item.mPackageName);
+ pw.print("mUserId............: "); pw.println(item.getUserId());
+ pw.print("mTargetPackageName.: "); pw.println(item.getTargetPackageName());
+ pw.print("mBaseCodePath......: "); pw.println(item.getBaseCodePath());
+ pw.print("mState.............: "); pw.println(OverlayInfo.stateToString(item.getState()));
+ pw.print("mIsEnabled.........: "); pw.println(item.isEnabled());
+ pw.print("mIsStatic..........: "); pw.println(item.isStatic());
+
+ pw.decreaseIndent();
+ pw.println("}");
}
}
@@ -527,12 +529,6 @@
.filter(item -> item.getTargetPackageName().equals(targetPackageName));
}
- private void assertNotNull(@Nullable final Object o) {
- if (o == null) {
- throw new AndroidRuntimeException("object must not be null");
- }
- }
-
static final class BadKeyException extends RuntimeException {
BadKeyException(@NonNull final String packageName, final int userId) {
super("Bad key mPackageName=" + packageName + " mUserId=" + userId);
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index f79f6f4..29f9f7c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -546,12 +546,12 @@
try {
code = mActivityManagerInternal.startActivitiesAsPackage(publisherPackage,
userId, intents, startActivityOptions);
- if (code >= ActivityManager.START_SUCCESS) {
+ if (ActivityManager.isStartResultSuccessful(code)) {
return true; // Success
} else {
Log.e(TAG, "Couldn't start activity, code=" + code);
}
- return code >= ActivityManager.START_SUCCESS;
+ return false;
} catch (SecurityException e) {
if (DEBUG) {
Slog.d(TAG, "SecurityException while launching intent", e);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0e91d30..24d08ac 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3185,6 +3185,17 @@
return null;
}
+ @Override
+ public @Nullable ComponentName getInstantAppResolverComponent() {
+ synchronized (mPackages) {
+ final Pair<ComponentName, String> instantAppResolver = getInstantAppResolverLPr();
+ if (instantAppResolver == null) {
+ return null;
+ }
+ return instantAppResolver.first;
+ }
+ }
+
private @Nullable Pair<ComponentName, String> getInstantAppResolverLPr() {
final String[] packageArray =
mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 3e920d4..bf92ce7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -148,6 +148,8 @@
return runSetHomeActivity();
case "get-privapp-permissions":
return runGetPrivappPermissions();
+ case "get-instantapp-resolver":
+ return runGetInstantAppResolver();
case "has-feature":
return runHasFeature();
default:
@@ -1272,6 +1274,21 @@
return 0;
}
+ private int runGetInstantAppResolver() {
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ final ComponentName instantAppsResolver = mInterface.getInstantAppResolverComponent();
+ if (instantAppsResolver == null) {
+ return 1;
+ }
+ pw.println(instantAppsResolver.flattenToString());
+ return 0;
+ } catch (Exception e) {
+ pw.println(e.toString());
+ return 1;
+ }
+ }
+
private int runHasFeature() {
final PrintWriter err = getErrPrintWriter();
final String featureName = getNextArg();
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index ac4b828..feeee3f 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -54,6 +54,7 @@
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Canvas;
import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Binder;
@@ -1356,7 +1357,7 @@
if (icon == null) {
return; // has no icon
}
-
+ int maxIconDimension = mMaxIconDimension;
Bitmap bitmap;
try {
switch (icon.getType()) {
@@ -1368,9 +1369,12 @@
return;
}
case Icon.TYPE_BITMAP:
- case Icon.TYPE_ADAPTIVE_BITMAP: {
bitmap = icon.getBitmap(); // Don't recycle in this case.
break;
+ case Icon.TYPE_ADAPTIVE_BITMAP: {
+ bitmap = icon.getBitmap(); // Don't recycle in this case.
+ maxIconDimension *= (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
+
}
default:
// This shouldn't happen because we've already validated the icon, but
@@ -1378,7 +1382,7 @@
throw ShortcutInfo.getInvalidIconException();
}
mShortcutBitmapSaver.saveBitmapLocked(shortcut,
- mMaxIconDimension, mIconPersistFormat, mIconPersistQuality);
+ maxIconDimension, mIconPersistFormat, mIconPersistQuality);
} finally {
// Once saved, we won't use the original icon information, so null it out.
shortcut.clearIcon();
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 1284b1b..0e8960e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -498,6 +498,7 @@
pkg.mRestrictedAccountType = "foo19";
pkg.mRequiredAccountType = "foo20";
pkg.mOverlayTarget = "foo21";
+ pkg.mOverlayPriority = 100;
pkg.mSigningKeys = new ArraySet<>();
pkg.mUpgradeKeySets = new ArraySet<>();
pkg.mKeySetMapping = new ArrayMap<>();
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index bd8492b3..48f07d6 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -45,6 +45,8 @@
public static final int CODE_LOCAL_IMS_SERVICE_DOWN = 106;
// No pending incoming call exists
public static final int CODE_LOCAL_NO_PENDING_CALL = 107;
+ // IMS Call ended during conference merge process
+ public static final int CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE = 108;
// IMS -> Telephony
// Service unavailable; by power off
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index c1f0038..f0163be 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -107,7 +107,7 @@
public void logTree() {
if (mAssistStructure != null) {
- mAssistStructure.dump();
+ mAssistStructure.dump(true);
}
}
diff --git a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
index 1156b01..1a4067f 100644
--- a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
+++ b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
@@ -17,4 +17,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.aapt.app.one" coreApp="true">
<uses-sdk android:minSdkVersion="21" />
+
+ <uses-permission-sdk-23 android:name="android.permission.TEST" android:maxSdkVersion="22" />
</manifest>
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index f998d31..53c66a6 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -295,6 +295,7 @@
manifest_action["original-package"];
manifest_action["protected-broadcast"];
manifest_action["uses-permission"];
+ manifest_action["uses-permission-sdk-23"];
manifest_action["permission"];
manifest_action["permission-tree"];
manifest_action["permission-group"];