Merge "Handle clear all button show and hide functionality for low ram devices" into oc-mr1-dev
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 00d6657..1a2dc5c 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -843,7 +843,7 @@
// Assumes forward playing from here on.
for (int i = 0; i < mEvents.size(); i++) {
AnimationEvent event = mEvents.get(i);
- if (event.getTime() > currentPlayTime) {
+ if (event.getTime() > currentPlayTime || event.getTime() == DURATION_INFINITE) {
break;
}
@@ -1264,7 +1264,8 @@
} else {
for (int i = mLastEventId + 1; i < size; i++) {
AnimationEvent event = mEvents.get(i);
- if (event.getTime() <= currentPlayTime) {
+ // TODO: need a function that accounts for infinite duration to compare time
+ if (event.getTime() != DURATION_INFINITE && event.getTime() <= currentPlayTime) {
latestId = i;
}
}
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 76643d6..54f74b1 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -174,7 +174,7 @@
*/
public Intent createConfirmFactoryResetCredentialIntent(
CharSequence title, CharSequence description, CharSequence alternateButtonLabel) {
- if (!LockPatternUtils.frpCredentialEnabled()) {
+ if (!LockPatternUtils.frpCredentialEnabled(mContext)) {
Log.w(TAG, "Factory reset credentials not supported.");
return null;
}
diff --git a/core/java/android/app/timezone/RulesUpdaterContract.java b/core/java/android/app/timezone/RulesUpdaterContract.java
index 9c62f46..2a22ead 100644
--- a/core/java/android/app/timezone/RulesUpdaterContract.java
+++ b/core/java/android/app/timezone/RulesUpdaterContract.java
@@ -51,7 +51,7 @@
* applies.
*/
public static final String ACTION_TRIGGER_RULES_UPDATE_CHECK =
- "android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK";
+ "com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK";
/**
* The extra containing the {@code byte[]} that should be passed to
@@ -61,7 +61,7 @@
* {@link #ACTION_TRIGGER_RULES_UPDATE_CHECK} intent has been processed.
*/
public static final String EXTRA_CHECK_TOKEN =
- "android.intent.extra.timezone.CHECK_TOKEN";
+ "com.android.intent.extra.timezone.CHECK_TOKEN";
/**
* Creates an intent that would trigger a time zone rules update check.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 744ee8e..d7ecc81 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2078,16 +2078,30 @@
* {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or
* due to device configuration.
*
+ * <p>If this app does not have permission to use this API, it will always
+ * return false rather than throw an exception.</p>
+ *
+ * <p>If the device has a hotspot provisioning app, the caller is required to hold the
+ * {@link android.Manifest.permission.TETHER_PRIVILEGED} permission.</p>
+ *
+ * <p>Otherwise, this method requires the caller to hold the ability to modify system
+ * settings as determined by {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @return a boolean - {@code true} indicating Tethering is supported.
*
* {@hide}
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+ @RequiresPermission(anyOf = {android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS})
public boolean isTetheringSupported() {
+ String pkgName = mContext.getOpPackageName();
try {
- String pkgName = mContext.getOpPackageName();
return mService.isTetheringSupported(pkgName);
+ } catch (SecurityException e) {
+ // This API is not available to this caller, but for backward-compatibility
+ // this will just return false instead of throwing.
+ return false;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/ParcelableException.java b/core/java/android/os/ParcelableException.java
index d84d629..7f71905 100644
--- a/core/java/android/os/ParcelableException.java
+++ b/core/java/android/os/ParcelableException.java
@@ -52,10 +52,12 @@
final String msg = in.readString();
try {
final Class<?> clazz = Class.forName(name, true, Parcelable.class.getClassLoader());
- return (Throwable) clazz.getConstructor(String.class).newInstance(msg);
+ if (Throwable.class.isAssignableFrom(clazz)) {
+ return (Throwable) clazz.getConstructor(String.class).newInstance(msg);
+ }
} catch (ReflectiveOperationException e) {
- throw new RuntimeException(name + ": " + msg);
}
+ return new RuntimeException(name + ": " + msg);
}
/** {@hide} */
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 3e08dcf..045c833 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -305,7 +305,7 @@
* <li>Use the {@link android.app.assist.AssistStructure.ViewNode#getWebDomain()} to get the
* source of the document.
* <li>Get the canonical domain using the
- * <a href="https://publicsuffix.org/>Public Suffix List</a> (see example below).
+ * <a href="https://publicsuffix.org/">Public Suffix List</a> (see example below).
* <li>Use <a href="https://developers.google.com/digital-asset-links/">Digital Asset Links</a>
* to obtain the package name and certificate fingerprint of the package corresponding to
* the canonical domain.
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index e64eb0d..1a9afcc 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -29,11 +29,12 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
import com.android.internal.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
/**
@@ -147,4 +148,9 @@
public String getSettingsActivity() {
return mSettingsActivity;
}
+
+ @Override
+ public String toString() {
+ return mServiceInfo == null ? "null" : mServiceInfo.toString();
+ }
}
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index 4951237..3af7e5d 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -159,11 +159,14 @@
* @return A bitmap of the given view or null if bounds has no width or height.
*/
public static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds) {
+ if (!view.isAttachedToWindow()) {
+ return null;
+ }
Bitmap bitmap = null;
int bitmapWidth = Math.round(bounds.width());
int bitmapHeight = Math.round(bounds.height());
if (bitmapWidth > 0 && bitmapHeight > 0) {
- float scale = Math.min(1f, ((float)MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight));
+ float scale = Math.min(1f, ((float) MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight));
bitmapWidth *= scale;
bitmapHeight *= scale;
matrix.postTranslate(-bounds.left, -bounds.top);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 22faeed..8f250a9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -7714,7 +7714,7 @@
public void onAccessibilityStateChanged(boolean enabled) {
if (enabled) {
ensureConnection();
- if (mAttachInfo.mHasWindowFocus) {
+ if (mAttachInfo.mHasWindowFocus && (mView != null)) {
mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
View focusedView = mView.findFocus();
if (focusedView != null && focusedView != mView) {
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index 5f47638..b4688bb 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -47,6 +47,19 @@
private final WindowPresenter mWindowPresenter;
private WindowManager.LayoutParams mWindowLayoutParams;
+ private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ /* ignore - handled by the super class */
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ dismiss();
+ }
+ };
+
/**
* Creates a popup window with a presenter owning the window and responsible for
* showing/hiding/updating the backing window. This can be useful of the window is
@@ -208,7 +221,21 @@
p.packageName = anchor.getContext().getPackageName();
mWindowPresenter.show(p, getTransitionEpicenter(), isLayoutInsetDecor(),
anchor.getLayoutDirection());
- return;
+ }
+
+ @Override
+ protected void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
+ super.attachToAnchor(anchor, xoff, yoff, gravity);
+ anchor.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
+ }
+
+ @Override
+ protected void detachFromAnchor() {
+ final View anchor = getAnchor();
+ if (anchor != null) {
+ anchor.removeOnAttachStateChangeListener(mOnAttachStateChangeListener);
+ }
+ super.detachFromAnchor();
}
@Override
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index b6034d1..aa172f9 100644
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -582,6 +582,7 @@
case ActionType.SMART_SHARE: // fall through
case ActionType.DRAG: // fall through
case ActionType.ABANDON: // fall through
+ case ActionType.OTHER: // fall through
return true;
default:
return false;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index bf25915..23ebadb 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -2296,8 +2296,8 @@
}
/** @hide */
- protected final void detachFromAnchor() {
- final View anchor = mAnchor != null ? mAnchor.get() : null;
+ protected void detachFromAnchor() {
+ final View anchor = getAnchor();
if (anchor != null) {
final ViewTreeObserver vto = anchor.getViewTreeObserver();
vto.removeOnScrollChangedListener(mOnScrollChangedListener);
@@ -2316,7 +2316,7 @@
}
/** @hide */
- protected final void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
+ protected void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
detachFromAnchor();
final ViewTreeObserver vto = anchor.getViewTreeObserver();
@@ -2339,6 +2339,11 @@
mAnchoredGravity = gravity;
}
+ /** @hide */
+ protected @Nullable View getAnchor() {
+ return mAnchor != null ? mAnchor.get() : null;
+ }
+
private void alignToAnchor() {
final View anchor = mAnchor != null ? mAnchor.get() : null;
if (anchor != null && anchor.isAttachedToWindow() && hasDecorView()) {
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 4ebb3cf..6c13e0c 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -49,6 +49,8 @@
@UiThread
final class SelectionActionModeHelper {
+ private static final String LOG_TAG = "SelectActionModeHelper";
+
/**
* Maximum time (in milliseconds) to wait for a result before timing out.
*/
@@ -68,14 +70,15 @@
mEditor = Preconditions.checkNotNull(editor);
mTextView = mEditor.getTextView();
mTextClassificationHelper = new TextClassificationHelper(
- mTextView.getTextClassifier(), mTextView.getText(),
+ mTextView.getTextClassifier(),
+ getText(mTextView),
0, 1, mTextView.getTextLocales());
mSelectionTracker = new SelectionTracker(mTextView);
}
public void startActionModeAsync(boolean adjustSelection) {
mSelectionTracker.onOriginalSelection(
- mTextView.getText(),
+ getText(mTextView),
mTextView.getSelectionStart(),
mTextView.getSelectionEnd(),
mTextView.isTextEditable());
@@ -164,7 +167,7 @@
}
private void startActionMode(@Nullable SelectionResult result) {
- final CharSequence text = mTextView.getText();
+ final CharSequence text = getText(mTextView);
if (result != null && text instanceof Spannable) {
Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
mTextClassification = result.mClassification;
@@ -196,7 +199,9 @@
}
private void resetTextClassificationHelper() {
- mTextClassificationHelper.reset(mTextView.getTextClassifier(), mTextView.getText(),
+ mTextClassificationHelper.reset(
+ mTextView.getTextClassifier(),
+ getText(mTextView),
mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
mTextView.getTextLocales());
}
@@ -216,6 +221,7 @@
private int mSelectionStart;
private int mSelectionEnd;
private boolean mAllowReset;
+ private final LogAbandonRunnable mDelayedLogAbandon = new LogAbandonRunnable();
SelectionTracker(TextView textView) {
mTextView = Preconditions.checkNotNull(textView);
@@ -227,6 +233,10 @@
*/
public void onOriginalSelection(
CharSequence text, int selectionStart, int selectionEnd, boolean editableText) {
+ // If we abandoned a selection and created a new one very shortly after, we may still
+ // have a pending request to log ABANDON, which we flush here.
+ mDelayedLogAbandon.flush();
+
mOriginalStart = mSelectionStart = selectionStart;
mOriginalEnd = mSelectionEnd = selectionEnd;
mAllowReset = false;
@@ -267,12 +277,7 @@
public void onSelectionDestroyed() {
mAllowReset = false;
// Wait a few ms to see if the selection was destroyed because of a text change event.
- mTextView.postDelayed(() -> {
- mLogger.logSelectionAction(
- mSelectionStart, mSelectionEnd,
- SelectionEvent.ActionType.ABANDON, null /* classification */);
- mSelectionStart = mSelectionEnd = -1;
- }, 100 /* ms */);
+ mDelayedLogAbandon.schedule(100 /* ms */);
}
/**
@@ -299,7 +304,7 @@
if (isSelectionStarted()
&& mAllowReset
&& textIndex >= mSelectionStart && textIndex <= mSelectionEnd
- && textView.getText() instanceof Spannable) {
+ && getText(textView) instanceof Spannable) {
mAllowReset = false;
boolean selected = editor.selectCurrentWord();
if (selected) {
@@ -329,6 +334,38 @@
private boolean isSelectionStarted() {
return mSelectionStart >= 0 && mSelectionEnd >= 0 && mSelectionStart != mSelectionEnd;
}
+
+ /** A helper for keeping track of pending abandon logging requests. */
+ private final class LogAbandonRunnable implements Runnable {
+ private boolean mIsPending;
+
+ /** Schedules an abandon to be logged with the given delay. Flush if necessary. */
+ void schedule(int delayMillis) {
+ if (mIsPending) {
+ Log.e(LOG_TAG, "Force flushing abandon due to new scheduling request");
+ flush();
+ }
+ mIsPending = true;
+ mTextView.postDelayed(this, delayMillis);
+ }
+
+ /** If there is a pending log request, execute it now. */
+ void flush() {
+ mTextView.removeCallbacks(this);
+ run();
+ }
+
+ @Override
+ public void run() {
+ if (mIsPending) {
+ mLogger.logSelectionAction(
+ mSelectionStart, mSelectionEnd,
+ SelectionEvent.ActionType.ABANDON, null /* classification */);
+ mSelectionStart = mSelectionEnd = -1;
+ mIsPending = false;
+ }
+ }
+ }
}
// TODO: Write tests
@@ -523,7 +560,7 @@
mSelectionResultSupplier = Preconditions.checkNotNull(selectionResultSupplier);
mSelectionResultCallback = Preconditions.checkNotNull(selectionResultCallback);
// Make a copy of the original text.
- mOriginalText = mTextView.getText().toString();
+ mOriginalText = getText(mTextView).toString();
}
@Override
@@ -539,7 +576,7 @@
@Override
@UiThread
protected void onPostExecute(SelectionResult result) {
- result = TextUtils.equals(mOriginalText, mTextView.getText()) ? result : null;
+ result = TextUtils.equals(mOriginalText, getText(mTextView)) ? result : null;
mSelectionResultCallback.accept(result);
}
@@ -668,8 +705,6 @@
}
}
-
-
@SelectionEvent.ActionType
private static int getActionType(int menuItemId) {
switch (menuItemId) {
@@ -690,4 +725,14 @@
return SelectionEvent.ActionType.OTHER;
}
}
+
+ private static CharSequence getText(TextView textView) {
+ // Extracts the textView's text.
+ // TODO: Investigate why/when TextView.getText() is null.
+ final CharSequence text = textView.getText();
+ if (text != null) {
+ return text;
+ }
+ return "";
+ }
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2cab009..eb639bd 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1450,11 +1450,16 @@
getFirstRowPosition(rowPosition + 1));
int serviceSpacing = holder.row.getContext().getResources()
.getDimensionPixelSize(R.dimen.chooser_service_spacing);
- int top = rowPosition == 0 ? serviceSpacing : 0;
- if (nextStartType != ChooserListAdapter.TARGET_SERVICE) {
- setVertPadding(holder, top, serviceSpacing);
+ if (rowPosition == 0 && nextStartType != ChooserListAdapter.TARGET_SERVICE) {
+ // if the row is the only row for target service
+ setVertPadding(holder, 0, 0);
} else {
- setVertPadding(holder, top, 0);
+ int top = rowPosition == 0 ? serviceSpacing : 0;
+ if (nextStartType != ChooserListAdapter.TARGET_SERVICE) {
+ setVertPadding(holder, top, serviceSpacing);
+ } else {
+ setVertPadding(holder, top, 0);
+ }
}
} else {
holder.row.setBackgroundColor(Color.TRANSPARENT);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f85333eb..5439906 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -303,7 +303,7 @@
}
public void reportFailedPasswordAttempt(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return;
}
getDevicePolicyManager().reportFailedPasswordAttempt(userId);
@@ -311,7 +311,7 @@
}
public void reportSuccessfulPasswordAttempt(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return;
}
getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
@@ -319,21 +319,21 @@
}
public void reportPasswordLockout(int timeoutMs, int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return;
}
getTrustManager().reportUnlockLockout(timeoutMs, userId);
}
public int getCurrentFailedPasswordAttempts(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return 0;
}
return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
}
public int getMaximumFailedPasswordsForWipe(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled()) {
+ if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
return 0;
}
return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
@@ -1768,11 +1768,12 @@
return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0;
}
- public static boolean userOwnsFrpCredential(UserInfo info) {
- return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled();
+ public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
+ return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled(context);
}
- public static boolean frpCredentialEnabled() {
- return FRP_CREDENTIAL_ENABLED;
+ public static boolean frpCredentialEnabled(Context context) {
+ return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
}
}
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index 76b3528..ee5c758 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -70,6 +70,8 @@
android:textSize="16sp"
android:textColor="#eeffffff"
android:layout_marginTop="4dp"
+ android:ellipsize="end"
+ android:maxLines="7"
/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9b1e4e1..b2727f8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1116,6 +1116,11 @@
<!-- Is the lock-screen disabled for new users by default -->
<bool name="config_disableLockscreenByDefault">false</bool>
+ <!-- If true, enables verification of the lockscreen credential in the factory reset protection
+ flow. This should be true if gatekeeper / weaver credentials can still be checked after a
+ factory reset. -->
+ <bool name="config_enableCredentialFactoryResetProtection">true</bool>
+
<!-- Control the behavior when the user long presses the home button.
0 - Nothing
1 - Launch all apps intent
@@ -1352,7 +1357,7 @@
<!-- The package of the time zone rules updater application. Expected to be the same
for all Android devices that support APK-based time zone rule updates.
- A package-targeted android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
+ A package-targeted com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
will be sent to the updater app if the system server detects an update to the updater or
data app packages.
The package referenced here must have the android.permission.UPDATE_TIME_ZONE_RULES
@@ -1363,7 +1368,7 @@
<!-- The package of the time zone rules data application. Expected to be configured
by OEMs to reference their own priv-app APK package.
- A package-targeted android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
+ A package-targeted com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
will be sent to the updater app if the system server detects an update to the updater or
data app packages.
[This is only used if config_enableUpdateableTimeZoneRules and
@@ -3018,7 +3023,7 @@
<bool name="config_handleVolumeKeysInWindowManager">false</bool>
<!-- Volume level of in-call notification tone playback [0..1] -->
- <item name="config_inCallNotificationVolume" format="float" type="dimen">.25</item>
+ <item name="config_inCallNotificationVolume" format="float" type="dimen">.10</item>
<!-- URI for in call notification sound -->
<string translatable="false" name="config_inCallNotificationSound">/system/media/audio/ui/InCallNotification.ogg</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ce6815f..5347719 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2679,6 +2679,8 @@
<string name="yes">OK</string>
<!-- Preference framework strings. -->
<string name="no">Cancel</string>
+ <!-- Preference framework strings. -->
+ <string name="close">CLOSE</string>
<!-- This is the generic "attention" string to be used in attention dialogs. Typically
combined with setIconAttribute(android.R.attr.alertDialogIcon)
(or setIcon(android.R.drawable.ic_dialog_alert) on legacy versions of the platform) -->
@@ -2811,6 +2813,11 @@
<!-- [CHAR LIMIT=200] Compat mode dialog: hint to re-enable compat mode dialog. -->
<string name="screen_compat_mode_hint">Re-enable this in System settings > Apps > Downloaded.</string>
+ <!-- Text of the alert that is displayed when a top application is killed by lmk. -->
+ <string name="top_app_killed_title">App isn\'t responding</string>
+ <!-- Top app killed by lmk dialog message. -->
+ <string name="top_app_killed_message"><xliff:g id="app_name">%1$s</xliff:g> may be using too much memory.</string>
+
<!-- [CHAR LIMIT=200] Unsupported display size dialog: message. Refers to "Display size" setting. -->
<string name="unsupported_display_size_message"><xliff:g id="app_name">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly.</string>
<!-- [CHAR LIMIT=50] Unsupported display size dialog: check box label. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 09d8c75..b36630e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1890,6 +1890,9 @@
<java-symbol type="string" name="anr_application_process" />
<java-symbol type="string" name="anr_process" />
<java-symbol type="string" name="anr_title" />
+ <java-symbol type="string" name="top_app_killed_title" />
+ <java-symbol type="string" name="top_app_killed_message" />
+ <java-symbol type="string" name="close" />
<java-symbol type="string" name="car_mode_disable_notification_message" />
<java-symbol type="string" name="car_mode_disable_notification_title" />
<java-symbol type="string" name="chooser_wallpaper" />
@@ -3019,6 +3022,8 @@
<java-symbol type="string" name="foreground_service_tap_for_details" />
<java-symbol type="string" name="foreground_service_multiple_separator" />
+ <java-symbol type="bool" name="config_enableCredentialFactoryResetProtection" />
+
<!-- ETWS primary messages -->
<java-symbol type="string" name="etws_primary_default_message_earthquake" />
<java-symbol type="string" name="etws_primary_default_message_tsunami" />
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 0209cea..40288f5 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -159,8 +159,10 @@
if (mNativeInstance == 0) {
mNativeInstance = createNativeInstance(mLocalMatrix == null
? 0 : mLocalMatrix.native_instance);
- mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
- this, mNativeInstance);
+ if (mNativeInstance != 0) {
+ mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+ this, mNativeInstance);
+ }
}
return mNativeInstance;
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index c3ef450..ceac325 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -31,6 +31,7 @@
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Shader;
+import android.os.Trace;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -605,38 +606,44 @@
public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
@NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
- if (mVectorState.mRootGroup != null || mVectorState.mNativeTree != null) {
- // This VD has been used to display other VD resource content, clean up.
- if (mVectorState.mRootGroup != null) {
- // Subtract the native allocation for all the nodes.
- VMRuntime.getRuntime().registerNativeFree(mVectorState.mRootGroup.getNativeSize());
- // Remove child nodes' reference to tree
- mVectorState.mRootGroup.setTree(null);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "VectorDrawable#inflate");
+ if (mVectorState.mRootGroup != null || mVectorState.mNativeTree != null) {
+ // This VD has been used to display other VD resource content, clean up.
+ if (mVectorState.mRootGroup != null) {
+ // Subtract the native allocation for all the nodes.
+ VMRuntime.getRuntime().registerNativeFree(
+ mVectorState.mRootGroup.getNativeSize());
+ // Remove child nodes' reference to tree
+ mVectorState.mRootGroup.setTree(null);
+ }
+ mVectorState.mRootGroup = new VGroup();
+ if (mVectorState.mNativeTree != null) {
+ // Subtract the native allocation for the tree wrapper, which contains root node
+ // as well as rendering related data.
+ VMRuntime.getRuntime().registerNativeFree(mVectorState.NATIVE_ALLOCATION_SIZE);
+ mVectorState.mNativeTree.release();
+ }
+ mVectorState.createNativeTree(mVectorState.mRootGroup);
}
- mVectorState.mRootGroup = new VGroup();
- if (mVectorState.mNativeTree != null) {
- // Subtract the native allocation for the tree wrapper, which contains root node
- // as well as rendering related data.
- VMRuntime.getRuntime().registerNativeFree(mVectorState.NATIVE_ALLOCATION_SIZE);
- mVectorState.mNativeTree.release();
- }
- mVectorState.createNativeTree(mVectorState.mRootGroup);
+ final VectorDrawableState state = mVectorState;
+ state.setDensity(Drawable.resolveDensity(r, 0));
+
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
+
+ mDpiScaledDirty = true;
+
+ state.mCacheDirty = true;
+ inflateChildElements(r, parser, attrs, theme);
+
+ state.onTreeConstructionFinished();
+ // Update local properties.
+ updateLocalState(r);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
- final VectorDrawableState state = mVectorState;
- state.setDensity(Drawable.resolveDensity(r, 0));
-
- final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawable);
- updateStateFromTypedArray(a);
- a.recycle();
-
- mDpiScaledDirty = true;
-
- state.mCacheDirty = true;
- inflateChildElements(r, parser, attrs, theme);
-
- state.onTreeConstructionFinished();
- // Update local properties.
- updateLocalState(r);
}
private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index f5bb821..69ead58 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -71,9 +71,11 @@
void AnimatorManager::pushStaging() {
if (mNewAnimators.size()) {
- LOG_ALWAYS_FATAL_IF(!mAnimationHandle,
- "Trying to start new animators on %p (%s) without an animation handle!",
- &mParent, mParent.getName());
+ if (CC_UNLIKELY(!mAnimationHandle)) {
+ ALOGW("Trying to start new animators on %p (%s) without an animation handle!",
+ &mParent, mParent.getName());
+ return;
+ }
// Only add new animators that are not already in the mAnimators list
for (auto& anim : mNewAnimators) {
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index f9a1cc5..2687410 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -280,6 +280,11 @@
bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread,
GlLayer& layer, SkBitmap* bitmap) {
+ if (!layer.isRenderable()) {
+ // layer has never been updated by DeferredLayerUpdater, abort copy
+ return false;
+ }
+
return CopyResult::Success == copyTextureInto(Caches::getInstance(),
renderThread.renderState(), layer.getTexture(), layer.getTexTransform(),
Rect(), bitmap);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 8a1de02..ca179c9 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -22,6 +22,7 @@
#include "SkShader.h"
#include <utils/Log.h>
#include "utils/Macros.h"
+#include "utils/TraceUtils.h"
#include "utils/VectorDrawableUtils.h"
#include <math.h>
@@ -593,14 +594,17 @@
void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
SkBitmap outCache;
bitmap.getSkBitmap(&outCache);
+ int cacheWidth = outCache.width();
+ int cacheHeight = outCache.height();
+ ATRACE_FORMAT("VectorDrawable repaint %dx%d", cacheWidth, cacheHeight);
outCache.eraseColor(SK_ColorTRANSPARENT);
SkCanvas outCanvas(outCache);
float viewportWidth = useStagingData ?
mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
float viewportHeight = useStagingData ?
mStagingProperties.getViewportHeight() : mProperties.getViewportHeight();
- float scaleX = outCache.width() / viewportWidth;
- float scaleY = outCache.height() / viewportHeight;
+ float scaleX = cacheWidth / viewportWidth;
+ float scaleY = cacheHeight / viewportHeight;
outCanvas.scale(scaleX, scaleY);
mRootNode->draw(&outCanvas, useStagingData);
}
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
new file mode 100644
index 0000000..04fc2d4
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+#include "TestSceneBase.h"
+#include "tests/common/BitmapAllocationTestUtils.h"
+#include "SkBlendMode.h"
+
+class TvApp;
+class TvAppNoRoundedCorner;
+class TvAppColorFilter;
+class TvAppNoRoundedCornerColorFilter;
+
+static bool _TvApp(
+ BitmapAllocationTestUtils::registerBitmapAllocationScene<TvApp>(
+ "tvapp", "A dense grid of cards:"
+ "with rounded corner, using overlay RenderNode for dimming."));
+
+static bool _TvAppNoRoundedCorner(
+ BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCorner>(
+ "tvapp_norc", "A dense grid of cards:"
+ "no rounded corner, using overlay RenderNode for dimming"));
+
+static bool _TvAppColorFilter(
+ BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppColorFilter>(
+ "tvapp_cf", "A dense grid of cards:"
+ "with rounded corner, using ColorFilter for dimming"));
+
+static bool _TvAppNoRoundedCornerColorFilter(
+ BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCornerColorFilter>(
+ "tvapp_norc_cf", "A dense grid of cards:"
+ "no rounded corner, using ColorFilter for dimming"));
+
+class TvApp : public TestScene {
+public:
+ TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ : TestScene()
+ , mAllocator(allocator) { }
+
+ sp<RenderNode> mBg;
+ std::vector<sp<RenderNode>> mCards;
+ std::vector<sp<RenderNode>> mInfoAreas;
+ std::vector<sp<RenderNode>> mImages;
+ std::vector<sp<RenderNode>> mOverlays;
+ std::vector<sk_sp<Bitmap>> mCachedBitmaps;
+ BitmapAllocationTestUtils::BitmapAllocator mAllocator;
+ sk_sp<Bitmap> mSingleBitmap;
+ int mSeed = 0;
+ int mSeed2 = 0;
+
+ void createContent(int width, int height, Canvas& canvas) override {
+ mBg = createBitmapNode(canvas, 0xFF9C27B0, 0, 0, width, height);
+ canvas.drawRenderNode(mBg.get());
+
+ canvas.insertReorderBarrier(true);
+ mSingleBitmap = mAllocator(dp(160), dp(120), kRGBA_8888_SkColorType,
+ [](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(0xFF0000FF);
+ });
+
+ for (int y = dp(18) - dp(178); y < height - dp(18); y += dp(178)) {
+ bool isFirstCard = true;
+ for (int x = dp(18); x < width - dp(18); x += dp(178)) {
+ sp<RenderNode> card = createCard(x, y, dp(160), dp(160), isFirstCard);
+ isFirstCard = false;
+ canvas.drawRenderNode(card.get());
+ mCards.push_back(card);
+ }
+ }
+ canvas.insertReorderBarrier(false);
+ }
+
+ void doFrame(int frameNr) override {
+ size_t numCards = mCards.size();
+ for (size_t ci = 0; ci < numCards; ci++) {
+ updateCard(ci, frameNr);
+ }
+ }
+
+private:
+ sp<RenderNode> createBitmapNode(Canvas& canvas, SkColor color, int left, int top,
+ int width, int height) {
+ return TestUtils::createNode(left, top, left + width , top + height,
+ [this, width, height, color](RenderProperties& props, Canvas& canvas) {
+ sk_sp<Bitmap> bitmap = mAllocator(width, height, kRGBA_8888_SkColorType,
+ [color](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(color);
+ });
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
+ }
+
+ sp<RenderNode> createSharedBitmapNode(Canvas& canvas, int left, int top,
+ int width, int height, sk_sp<Bitmap>bitmap) {
+ return TestUtils::createNode(left, top, left + width , top + height,
+ [bitmap](RenderProperties& props, Canvas& canvas) {
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
+ }
+
+ sp<RenderNode> createInfoNode(Canvas& canvas, int left, int top,
+ int width, int height, const char* text, const char* text2) {
+ return TestUtils::createNode(left, top, left + width , top + height,
+ [text, text2](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
+
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(24);
+
+ paint.setColor(Color::Black);
+ TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 10, 30);
+ paint.setTextSize(20);
+ TestUtils::drawUtf8ToCanvas(&canvas, text2, paint, 10, 54);
+
+ });
+ }
+
+ sp<RenderNode> createColorNode(Canvas& canvas, int left, int top,
+ int width, int height, SkColor color) {
+ return TestUtils::createNode(left, top, left + width , top + height,
+ [color](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(color, SkBlendMode::kSrcOver);
+ });
+ }
+
+ virtual bool useSingleBitmap() {
+ return false;
+ }
+
+ virtual float roundedCornerRadius() {
+ return dp(2);
+ }
+
+ // when true, use overlay RenderNode for dimming, otherwise apply a ColorFilter to dim image
+ virtual bool useOverlay() {
+ return true;
+ }
+
+ sp<RenderNode> createCard(int x, int y, int width, int height, bool selected) {
+ return TestUtils::createNode(x, y, x + width, y + height,
+ [width, height, selected, this](RenderProperties& props, Canvas& canvas) {
+ if (selected) {
+ props.setElevation(dp(16));
+ props.setScaleX(1.2);
+ props.setScaleY(1.2);
+ }
+ props.mutableOutline().setRoundRect(0, 0, width, height, roundedCornerRadius(), 1);
+ props.mutableOutline().setShouldClip(true);
+
+ sk_sp<Bitmap> bitmap = useSingleBitmap() ? mSingleBitmap
+ : mAllocator(width, dp(120), kRGBA_8888_SkColorType, [this](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(0xFF000000 | ((mSeed << 3) & 0xFF));
+ });
+ sp<RenderNode> cardImage = createSharedBitmapNode(canvas, 0, 0, width, dp(120),
+ bitmap);
+ canvas.drawRenderNode(cardImage.get());
+ mCachedBitmaps.push_back(bitmap);
+ mImages.push_back(cardImage);
+
+ char buffer[128];
+ sprintf(buffer, "Video %d-%d", mSeed, mSeed + 1);
+ mSeed++;
+ char buffer2[128];
+ sprintf(buffer2, "Studio %d", mSeed2++);
+ sp<RenderNode> infoArea = createInfoNode(canvas, 0, dp(120), width, height, buffer, buffer2);
+ canvas.drawRenderNode(infoArea.get());
+ mInfoAreas.push_back(infoArea);
+
+ if (useOverlay()) {
+ sp<RenderNode> overlayColor = createColorNode(canvas, 0, 0, width, height, 0x00000000);
+ canvas.drawRenderNode(overlayColor.get());
+ mOverlays.push_back(overlayColor);
+ }
+ });
+ }
+
+ void updateCard(int ci, int curFrame) {
+ // updating card's translation Y
+ sp<RenderNode> card = mCards[ci];
+ card->setPropertyFieldsDirty(RenderNode::Y);
+ card->mutateStagingProperties().setTranslationY(curFrame % 150);
+
+ // re-recording card's canvas, not necessary but to add some burden to CPU
+ std::unique_ptr<Canvas> cardcanvas(Canvas::create_recording_canvas(
+ card->stagingProperties().getWidth(),
+ card->stagingProperties().getHeight()));
+ sp<RenderNode> image = mImages[ci];
+ sp<RenderNode> infoArea = mInfoAreas[ci];
+ cardcanvas->drawRenderNode(infoArea.get());
+
+ if (useOverlay()) {
+ cardcanvas->drawRenderNode(image.get());
+ // re-recording card overlay's canvas, animating overlay color alpha
+ sp<RenderNode> overlay = mOverlays[ci];
+ std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
+ overlay->stagingProperties().getWidth(),
+ overlay->stagingProperties().getHeight()));
+ canvas->drawColor((curFrame % 150) << 24, SkBlendMode::kSrcOver);
+ overlay->setStagingDisplayList(canvas->finishRecording());
+ cardcanvas->drawRenderNode(overlay.get());
+ } else {
+ // re-recording image node's canvas, animating ColorFilter
+ std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
+ image->stagingProperties().getWidth(),
+ image->stagingProperties().getHeight()));
+ SkPaint paint;
+ sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter((curFrame % 150) << 24,
+ SkBlendMode::kSrcATop));
+ paint.setColorFilter(filter);
+ sk_sp<Bitmap> bitmap = mCachedBitmaps[ci];
+ canvas->drawBitmap(*bitmap, 0, 0, &paint);
+ image->setStagingDisplayList(canvas->finishRecording());
+ cardcanvas->drawRenderNode(image.get());
+ }
+
+ card->setStagingDisplayList(cardcanvas->finishRecording());
+ }
+};
+
+class TvAppNoRoundedCorner : public TvApp {
+public:
+ TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ : TvApp(allocator) { }
+
+private:
+
+ virtual float roundedCornerRadius() override {
+ return dp(0);
+ }
+};
+
+class TvAppColorFilter : public TvApp {
+public:
+ TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ : TvApp(allocator) { }
+
+private:
+
+ virtual bool useOverlay() override {
+ return false;
+ }
+};
+
+class TvAppNoRoundedCornerColorFilter : public TvApp {
+public:
+ TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ : TvApp(allocator) { }
+
+private:
+
+ virtual float roundedCornerRadius() override {
+ return dp(0);
+ }
+
+ virtual bool useOverlay() override {
+ return false;
+ }
+};
+
+
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index dc7fa8c..3308fc9 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -28,7 +28,6 @@
MediaRouterClientState getState(IMediaRouterClient client);
boolean isPlaybackActive(IMediaRouterClient client);
- boolean isGlobalBluetoothA2doOn();
void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan);
void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index b072f65..013e85e 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -184,25 +184,33 @@
void updateAudioRoutes(AudioRoutesInfo newRoutes) {
boolean audioRoutesChanged = false;
+ boolean forceUseDefaultRoute = false;
+
if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
mCurAudioRoutesInfo.mainType = newRoutes.mainType;
int name;
- if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0
- || (newRoutes.mainType&AudioRoutesInfo.MAIN_HEADSET) != 0) {
+ if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0
+ || (newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
name = com.android.internal.R.string.default_audio_route_name_headphones;
- } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
+ } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
- } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
+ } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
name = com.android.internal.R.string.default_media_route_name_hdmi;
} else {
name = com.android.internal.R.string.default_audio_route_name;
}
mDefaultAudioVideo.mNameResId = name;
dispatchRouteChanged(mDefaultAudioVideo);
+
+ if ((newRoutes.mainType & (AudioRoutesInfo.MAIN_HEADSET
+ | AudioRoutesInfo.MAIN_HEADPHONES | AudioRoutesInfo.MAIN_USB)) != 0) {
+ forceUseDefaultRoute = true;
+ }
audioRoutesChanged = true;
}
if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
+ forceUseDefaultRoute = false;
mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
if (mCurAudioRoutesInfo.bluetoothName != null) {
if (mBluetoothA2dpRoute == null) {
@@ -231,30 +239,18 @@
Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo
|| mSelectedRoute == mBluetoothA2dpRoute) {
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
+ if (forceUseDefaultRoute || mBluetoothA2dpRoute == null) {
+ selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
+ } else {
+ selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false);
+ }
}
}
}
- RouteInfo getDefaultSystemAudioRoute() {
- boolean globalBluetoothA2doOn = false;
- try {
- globalBluetoothA2doOn = mMediaRouterService.isGlobalBluetoothA2doOn();
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to call isSystemBluetoothA2doOn.", ex);
- }
- return (globalBluetoothA2doOn && mBluetoothA2dpRoute != null)
- ? mBluetoothA2dpRoute : mDefaultAudioVideo;
- }
-
- RouteInfo getCurrentSystemAudioRoute() {
- return (isBluetoothA2dpOn() && mBluetoothA2dpRoute != null)
- ? mBluetoothA2dpRoute : mDefaultAudioVideo;
- }
-
boolean isBluetoothA2dpOn() {
try {
- return mAudioService.isBluetoothA2dpOn();
+ return mBluetoothA2dpRoute != null && mAudioService.isBluetoothA2dpOn();
} catch (RemoteException e) {
Log.e(TAG, "Error querying Bluetooth A2DP state", e);
return false;
@@ -608,6 +604,7 @@
|| mSelectedRoute == null) {
return;
}
+ Log.v(TAG, "onRestoreRoute() : a2dp=" + isBluetoothA2dpOn());
mSelectedRoute.select();
}
}
@@ -940,10 +937,12 @@
Log.v(TAG, "Selecting route: " + route);
assert(route != null);
final RouteInfo oldRoute = sStatic.mSelectedRoute;
+ final RouteInfo currentSystemRoute = sStatic.isBluetoothA2dpOn()
+ ? sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo;
boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo
|| oldRoute == sStatic.mBluetoothA2dpRoute);
if (oldRoute == route
- && (!wasDefaultOrBluetoothRoute || route == sStatic.getCurrentSystemAudioRoute())) {
+ && (!wasDefaultOrBluetoothRoute || route == currentSystemRoute)) {
return;
}
if (!route.matchesTypes(types)) {
@@ -1014,8 +1013,7 @@
static void selectDefaultRouteStatic() {
// TODO: Be smarter about the route types here; this selects for all valid.
- if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute
- && sStatic.mBluetoothA2dpRoute != null && sStatic.isBluetoothA2dpOn()) {
+ if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute && sStatic.isBluetoothA2dpOn()) {
selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false);
} else {
selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false);
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java
index b7fd404..3c5ac8d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java
@@ -73,7 +73,7 @@
final Drawable deviceDrawable = context.getDrawable(resId);
final BatteryMeterDrawable batteryDrawable = new BatteryMeterDrawable(context,
- R.color.meter_background_color, batteryLevel);
+ context.getColor(R.color.meter_background_color), batteryLevel);
final int pad = context.getResources().getDimensionPixelSize(R.dimen.bt_battery_padding);
batteryDrawable.setPadding(pad, pad, pad, pad);
@@ -107,6 +107,8 @@
@VisibleForTesting
static class BatteryMeterDrawable extends BatteryMeterDrawableBase {
private final float mAspectRatio;
+ @VisibleForTesting
+ int mFrameColor;
public BatteryMeterDrawable(Context context, int frameColor, int batteryLevel) {
super(context, frameColor);
@@ -118,6 +120,7 @@
final int tintColor = Utils.getColorAttr(context, android.R.attr.colorControlNormal);
setColorFilter(new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN));
setBatteryLevel(batteryLevel);
+ mFrameColor = frameColor;
}
@Override
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
index 76760a9..adec402 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
@@ -100,4 +100,15 @@
assertThat(twinDrawable.getLayerInsetTop(1)).isEqualTo(
drawable.getLayerInsetTop(1));
}
+
+ @Test
+ public void testCreateLayerDrawable_bluetoothDrawable_hasCorrectFrameColor() {
+ BluetoothDeviceLayerDrawable drawable = BluetoothDeviceLayerDrawable.createLayerDrawable(
+ mContext, RES_ID, BATTERY_LEVEL);
+ BluetoothDeviceLayerDrawable.BatteryMeterDrawable batteryMeterDrawable =
+ (BluetoothDeviceLayerDrawable.BatteryMeterDrawable) drawable.getDrawable(1);
+
+ assertThat(batteryMeterDrawable.mFrameColor).isEqualTo(
+ mContext.getColor(R.color.meter_background_color));
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index d95402c..cd23c97 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1069,6 +1069,7 @@
cb.onDreamingStateChanged(mIsDreaming);
}
}
+ updateFingerprintListeningState();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 03407e2..4bb4e79 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -22,6 +22,7 @@
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
+import android.os.Trace;
import com.android.internal.annotations.VisibleForTesting;
@@ -94,9 +95,14 @@
@Override
public void onSensorChanged(SensorEvent event) {
- if (mRegistered) {
- mLastSensorValue = (int) event.values[0];
- updateBrightnessAndReady();
+ Trace.beginSection("DozeScreenBrightness.onSensorChanged" + event.values[0]);
+ try {
+ if (mRegistered) {
+ mLastSensorValue = (int) event.values[0];
+ updateBrightnessAndReady();
+ }
+ } finally {
+ Trace.endSection();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
new file mode 100644
index 0000000..2c7ec70
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
@@ -0,0 +1,86 @@
+/*
+ * 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 com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import com.android.systemui.qs.tileimpl.SlashImageView;
+
+
+/**
+ * Creates AlphaControlledSlashImageView instead of SlashImageView
+ */
+public class AlphaControlledSignalTileView extends SignalTileView {
+ public AlphaControlledSignalTileView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected SlashImageView createSlashImageView(Context context) {
+ return new AlphaControlledSlashImageView(context);
+ }
+
+ /**
+ * Creates AlphaControlledSlashDrawable instead of regular SlashDrawables
+ */
+ public static class AlphaControlledSlashImageView extends SlashImageView {
+ public AlphaControlledSlashImageView(Context context) {
+ super(context);
+ }
+
+ public void setFinalImageTintList(ColorStateList tint) {
+ super.setImageTintList(tint);
+ final SlashDrawable slash = getSlash();
+ if (slash != null) {
+ ((AlphaControlledSlashDrawable)slash).setFinalTintList(tint);
+ }
+ }
+
+ @Override
+ protected void ensureSlashDrawable() {
+ if (getSlash() == null) {
+ final SlashDrawable slash = new AlphaControlledSlashDrawable(getDrawable());
+ setSlash(slash);
+ slash.setAnimationEnabled(getAnimationEnabled());
+ setImageViewDrawable(slash);
+ }
+ }
+ }
+
+ /**
+ * SlashDrawable that disobeys orders to change its drawable's tint except when you tell
+ * it not to disobey. The slash still will animate its alpha.
+ */
+ public static class AlphaControlledSlashDrawable extends SlashDrawable {
+ AlphaControlledSlashDrawable(Drawable d) {
+ super(d);
+ }
+
+ @Override
+ protected void setDrawableTintList(ColorStateList tint) {
+ }
+
+ /**
+ * Set a target tint list instead of
+ */
+ public void setFinalTintList(ColorStateList tint) {
+ super.setDrawableTintList(tint);
+ }
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index b300e4a..9ee40cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -63,13 +63,17 @@
@Override
protected View createIcon() {
mIconFrame = new FrameLayout(mContext);
- mSignal = new SlashImageView(mContext);
+ mSignal = createSlashImageView(mContext);
mIconFrame.addView(mSignal);
mOverlay = new ImageView(mContext);
mIconFrame.addView(mOverlay, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
return mIconFrame;
}
+ protected SlashImageView createSlashImageView(Context context) {
+ return new SlashImageView(context);
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
index c356148..a9b2376 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
@@ -197,11 +197,15 @@
public void setTintList(@Nullable ColorStateList tint) {
mTintList = tint;
super.setTintList(tint);
- mDrawable.setTintList(tint);
+ setDrawableTintList(tint);
mPaint.setColor(tint.getDefaultColor());
invalidateSelf();
}
+ protected void setDrawableTintList(@Nullable ColorStateList tint) {
+ mDrawable.setTintList(tint);
+ }
+
@Override
public void setTintMode(@NonNull Mode tintMode) {
mTintMode = tintMode;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 8074cb9..e8c8b90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -33,6 +33,7 @@
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashImageView;
import java.util.Objects;
public class QSIconViewImpl extends QSIconView {
@@ -138,7 +139,12 @@
animateGrayScale(mTint, color, iv);
mTint = color;
} else {
- setTint(iv, color);
+ if (iv instanceof AlphaControlledSlashImageView) {
+ ((AlphaControlledSlashImageView)iv)
+ .setFinalImageTintList(ColorStateList.valueOf(color));
+ } else {
+ setTint(iv, color);
+ }
mTint = color;
}
}
@@ -149,6 +155,10 @@
}
public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
+ if (iv instanceof AlphaControlledSlashImageView) {
+ ((AlphaControlledSlashImageView)iv)
+ .setFinalImageTintList(ColorStateList.valueOf(toColor));
+ }
if (ValueAnimator.areAnimatorsEnabled()) {
final float fromAlpha = Color.alpha(fromColor);
final float toAlpha = Color.alpha(toColor);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
index 97e9c3d..63d6f82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
@@ -34,7 +34,15 @@
super(context);
}
- private void ensureSlashDrawable() {
+ protected SlashDrawable getSlash() {
+ return mSlash;
+ }
+
+ protected void setSlash(SlashDrawable slash) {
+ mSlash = slash;
+ }
+
+ protected void ensureSlashDrawable() {
if (mSlash == null) {
mSlash = new SlashDrawable(getDrawable());
mSlash.setAnimationEnabled(mAnimationEnabled);
@@ -56,10 +64,18 @@
}
}
+ protected void setImageViewDrawable(SlashDrawable slash) {
+ super.setImageDrawable(slash);
+ }
+
public void setAnimationEnabled(boolean enabled) {
mAnimationEnabled = enabled;
}
+ public boolean getAnimationEnabled() {
+ return mAnimationEnabled;
+ }
+
private void setSlashState(@NonNull SlashState slashState) {
ensureSlashDrawable();
mSlash.setRotation(slashState.rotation);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 33b1512..2370273 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -37,10 +37,10 @@
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.SignalState;
+import com.android.systemui.qs.AlphaControlledSignalTileView;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.SignalTileView;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
@@ -104,7 +104,7 @@
@Override
public QSIconView createTileView(Context context) {
- return new SignalTileView(context);
+ return new AlphaControlledSignalTileView(context);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 6bfef20..23a7dae 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -64,6 +64,7 @@
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
@@ -1210,6 +1211,10 @@
}
}
+ public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
+ saveSnapTargetBeforeMinimized(mSnapAlgorithm.getMiddleTarget());
+ }
+
public final void onBusEvent(DockedTopTaskEvent event) {
if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
mState.growAfterRecentsDrawn = false;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java
new file mode 100644
index 0000000..3e677c0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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 com.android.systemui.qs;
+
+
+import static org.junit.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashDrawable;
+import com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashImageView;
+import org.junit.Test;
+
+@SmallTest
+public class AlphaControlledSignalTileViewTest extends SysuiTestCase {
+
+ private AlphaControlledSignalTileView mTileView;
+
+ @Test
+ public void testTileView_createsAlphaControlledSlashImageView() {
+ mTileView = new AlphaControlledSignalTileView(mContext);
+
+ assertTrue(mTileView.createSlashImageView(mContext)
+ instanceof AlphaControlledSlashImageView);
+ }
+
+ /// AlphaControlledSlashImageView tests
+ @Test
+ public void testSlashImageView_createsAlphaControlledSlashDrawable() {
+ TestableSlashImageView iv = new TestableSlashImageView(mContext);
+
+ iv.ensureSlashDrawable();
+ assertTrue(iv.getSlashDrawable() instanceof AlphaControlledSlashDrawable);
+ }
+
+ /// AlphaControlledSlashDrawable tests
+ @Test
+ public void testSlashDrawable_doesNotSetTintList() {
+ Drawable mockDrawable = mock(Drawable.class);
+ AlphaControlledSlashDrawable drawable = new AlphaControlledSlashDrawable(mockDrawable);
+ ColorStateList list = ColorStateList.valueOf(0xffffff);
+ drawable.setTintList(list);
+ verify(mockDrawable, never()).setTintList(any());
+ }
+
+ @Test
+ public void testSlashDrawable_setsFinalTintList() {
+ Drawable mockDrawable = mock(Drawable.class);
+ AlphaControlledSlashDrawable drawable = new AlphaControlledSlashDrawable(mockDrawable);
+ ColorStateList list = ColorStateList.valueOf(0xffffff);
+ drawable.setFinalTintList(list);
+ verify(mockDrawable, atLeastOnce()).setTintList(list);
+ }
+
+ // Expose getSlashDrawable
+ private static class TestableSlashImageView extends AlphaControlledSlashImageView {
+ TestableSlashImageView(Context c) {
+ super(c);
+ }
+
+ private SlashDrawable getSlashDrawable() {
+ return mSlash;
+ }
+
+ @Override
+ protected void setSlash(SlashDrawable slash) {
+ super.setSlash(slash);
+ }
+ }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index f15749f..54c9ec5 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4527,6 +4527,17 @@
// Type TYPE_FAILURE: An invalid opperation was reported by the app's AutofillManager
AUTOFILL_PENDING_SAVE_UI_OPERATION = 1134;
+ // Autofill service called API that disables itself
+ // Package: Package of the autofill service
+ // OS: O MR
+ AUTOFILL_SERVICE_DISABLED_SELF = 1135;
+
+ // Counter showing how long it took (in ms) to show the autofill UI after a field was focused
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // Package: Package of the autofill service
+ // OS: O MR
+ AUTOFILL_UI_LATENCY = 1136;
+
// ---- End O-MR1 Constants, all O-MR1 constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index b9bea16..1f4161a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -115,6 +115,7 @@
private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray();
private final LocalLog mRequestsHistory = new LocalLog(20);
+ private final LocalLog mUiLatencyHistory = new LocalLog(20);
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -306,7 +307,7 @@
AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId);
if (service == null) {
service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory,
- resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId));
+ mUiLatencyHistory, resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId));
mServicesCache.put(userId, service);
}
return service;
@@ -736,6 +737,8 @@
if (showHistory) {
pw.println("Requests history:");
mRequestsHistory.reverseDump(fd, pw, args);
+ pw.println("UI latency history:");
+ mUiLatencyHistory.reverseDump(fd, pw, args);
}
} finally {
setDebugLocked(oldDebug);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4705f1e..3a3b570 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -35,6 +35,7 @@
import android.content.pm.ServiceInfo;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
@@ -63,6 +64,8 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.HandlerCaller;
import com.android.server.autofill.ui.AutoFillUI;
@@ -89,6 +92,7 @@
private final Context mContext;
private final Object mLock;
private final AutoFillUI mUi;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
private RemoteCallbackList<IAutoFillManagerClient> mClients;
private AutofillServiceInfo mInfo;
@@ -96,6 +100,8 @@
private static final Random sRandom = new Random();
private final LocalLog mRequestsHistory;
+ private final LocalLog mUiLatencyHistory;
+
/**
* Whether service was disabled for user due to {@link UserManager} restrictions.
*/
@@ -137,10 +143,11 @@
private long mLastPrune = 0;
AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
- int userId, AutoFillUI ui, boolean disabled) {
+ LocalLog uiLatencyHistory, int userId, AutoFillUI ui, boolean disabled) {
mContext = context;
mLock = lock;
mRequestsHistory = requestsHistory;
+ mUiLatencyHistory = uiLatencyHistory;
mUserId = userId;
mUi = ui;
updateLocked(disabled);
@@ -218,8 +225,10 @@
if (serviceInfo != null) {
mInfo = new AutofillServiceInfo(mContext.getPackageManager(),
serviceComponent, mUserId);
+ if (sDebug) Slog.d(TAG, "Set component for user " + mUserId + " as " + mInfo);
} else {
mInfo = null;
+ if (sDebug) Slog.d(TAG, "Reset component for user " + mUserId);
}
final boolean isEnabled = isEnabled();
if (wasEnabled != isEnabled) {
@@ -345,17 +354,31 @@
}
void disableOwnedAutofillServicesLocked(int uid) {
- if (mInfo == null || mInfo.getServiceInfo().applicationInfo.uid != uid) {
+ Slog.i(TAG, "disableOwnedServices(" + uid + "): " + mInfo);
+ if (mInfo == null) return;
+
+ final ServiceInfo serviceInfo = mInfo.getServiceInfo();
+ if (serviceInfo.applicationInfo.uid != uid) {
+ Slog.w(TAG, "disableOwnedServices(): ignored when called by UID " + uid
+ + " instead of " + serviceInfo.applicationInfo.uid
+ + " for service " + mInfo);
return;
}
+
+
final long identity = Binder.clearCallingIdentity();
try {
final String autoFillService = getComponentNameFromSettings();
- if (mInfo.getServiceInfo().getComponentName().equals(
- ComponentName.unflattenFromString(autoFillService))) {
+ final ComponentName componentName = serviceInfo.getComponentName();
+ if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) {
+ mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF,
+ componentName.getPackageName());
Settings.Secure.putStringForUser(mContext.getContentResolver(),
Settings.Secure.AUTOFILL_SERVICE, null, mUserId);
destroySessionsLocked();
+ } else {
+ Slog.w(TAG, "disableOwnedServices(): ignored because current service ("
+ + serviceInfo + ") does not match Settings (" + autoFillService + ")");
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -379,7 +402,7 @@
final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
sessionId, uid, activityToken, appCallbackToken, hasCallback,
- mInfo.getServiceInfo().getComponentName(), packageName);
+ mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), packageName);
mSessions.put(newSession.id, newSession);
return newSession;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 2d10aff..905db67 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -50,6 +50,7 @@
import android.os.IBinder;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.service.autofill.AutofillService;
import android.service.autofill.Dataset;
import android.service.autofill.FillContext;
@@ -61,8 +62,10 @@
import android.service.autofill.ValueFinder;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.LocalLog;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TimeUtils;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -177,6 +180,20 @@
private PendingUi mPendingSaveUi;
/**
+ * When the session started (using elapsed time since boot).
+ */
+ private final long mStartTime;
+
+ /**
+ * When the UI was shown for the first time (using elapsed time since boot).
+ */
+ @GuardedBy("mLock")
+ private long mUiShownTime;
+
+ @GuardedBy("mLock")
+ private final LocalLog mUiLatencyHistory;
+
+ /**
* Receiver of assist data from the app's {@link Activity}.
*/
private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
@@ -397,10 +414,11 @@
Session(@NonNull AutofillManagerServiceImpl service, @NonNull AutoFillUI ui,
@NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
@NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
- @NonNull IBinder client, boolean hasCallback,
+ @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
@NonNull ComponentName componentName, @NonNull String packageName) {
id = sessionId;
this.uid = uid;
+ mStartTime = SystemClock.elapsedRealtime();
mService = service;
mLock = lock;
mUi = ui;
@@ -408,6 +426,7 @@
mRemoteFillService = new RemoteFillService(context, componentName, userId, this);
mActivityToken = activityToken;
mHasCallback = hasCallback;
+ mUiLatencyHistory = uiLatencyHistory;
mPackageName = packageName;
mClient = IAutoFillManagerClient.Stub.asInterface(client);
@@ -1347,6 +1366,31 @@
getUiForShowing().showFillUi(filledId, response, filterText,
mService.getServicePackageName(), mPackageName, this);
+
+ synchronized (mLock) {
+ if (mUiShownTime == 0) {
+ // Log first time UI is shown.
+ mUiShownTime = SystemClock.elapsedRealtime();
+ final long duration = mUiShownTime - mStartTime;
+ if (sDebug) {
+ final StringBuilder msg = new StringBuilder("1st UI for ")
+ .append(mActivityToken)
+ .append(" shown in ");
+ TimeUtils.formatDuration(duration, msg);
+ Slog.d(TAG, msg.toString());
+ }
+ final StringBuilder historyLog = new StringBuilder("id=").append(id)
+ .append(" app=").append(mActivityToken)
+ .append(" svc=").append(mService.getServicePackageName())
+ .append(" latency=");
+ TimeUtils.formatDuration(duration, historyLog);
+ mUiLatencyHistory.log(historyLog.toString());
+
+ final LogMaker metricsLog = newLogMaker(MetricsEvent.AUTOFILL_UI_LATENCY)
+ .setCounterValue((int) duration);
+ mMetricsLogger.write(metricsLog);
+ }
+ }
}
boolean isDestroyed() {
@@ -1655,6 +1699,14 @@
pw.print(prefix); pw.print("uid: "); pw.println(uid);
pw.print(prefix); pw.print("mPackagename: "); pw.println(mPackageName);
pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
+ pw.print(prefix); pw.print("mStartTime: "); pw.println(mStartTime);
+ pw.print(prefix); pw.print("Time to show UI: ");
+ if (mUiShownTime == 0) {
+ pw.println("N/A");
+ } else {
+ TimeUtils.formatDuration(mUiShownTime - mStartTime, pw);
+ pw.println();
+ }
pw.print(prefix); pw.print("mResponses: ");
if (mResponses == null) {
pw.println("null");
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index cd9bdb7..d48f23c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -271,6 +271,10 @@
mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel);
mDialog.setContentView(view);
+ // Dialog can be dismissed when touched outside, but the negative listener should not be
+ // notified (hence the null argument).
+ mDialog.setOnDismissListener((d) -> mListener.onCancel(null));
+
final Window window = mDialog.getWindow();
window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e70a294..9afa825 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.NETID_UNSET;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.getNetworkTypeName;
@@ -90,6 +91,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -781,6 +783,13 @@
mNetworksDefined++; // used only in the log() statement below.
}
+ // Do the same for Ethernet, since it's often not specified in the configs, although many
+ // devices can use it via USB host adapters.
+ if (mNetConfigs[TYPE_ETHERNET] == null && hasService(Context.ETHERNET_SERVICE)) {
+ mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
+ mNetworksDefined++;
+ }
+
if (VDBG) log("mNetworksDefined=" + mNetworksDefined);
mProtectedNetworks = new ArrayList<Integer>();
@@ -2205,7 +2214,7 @@
// A network factory has connected. Send it all current NetworkRequests.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (nri.request.isListen()) continue;
- NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+ NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
(nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
}
@@ -2282,9 +2291,9 @@
// Remove all previously satisfied requests.
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest request = nai.requestAt(i);
- NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
+ NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
- mNetworkForRequestId.remove(request.requestId);
+ clearNetworkForRequest(request.requestId);
sendUpdatedScoreToFactories(request, 0);
}
}
@@ -2360,7 +2369,7 @@
}
}
rematchAllNetworksAndRequests(null, 0);
- if (nri.request.isRequest() && mNetworkForRequestId.get(nri.request.requestId) == null) {
+ if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {
sendUpdatedScoreToFactories(nri.request, 0);
}
}
@@ -2415,7 +2424,7 @@
// 2. Unvalidated WiFi will not be reaped when validated cellular
// is currently satisfying the request. This is desirable when
// WiFi ends up validating and out scoring cellular.
- mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
+ getNetworkForRequest(nri.request.requestId).getCurrentScore() <
nai.getCurrentScoreAsValidated())) {
return false;
}
@@ -2442,7 +2451,7 @@
if (mNetworkRequests.get(nri.request) == null) {
return;
}
- if (mNetworkForRequestId.get(nri.request.requestId) != null) {
+ if (getNetworkForRequest(nri.request.requestId) != null) {
return;
}
if (VDBG || (DBG && nri.request.isRequest())) {
@@ -2482,7 +2491,7 @@
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.request.isRequest()) {
boolean wasKept = false;
- NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+ NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
if (nai != null) {
boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
nai.removeRequest(nri.request.requestId);
@@ -2499,7 +2508,7 @@
} else {
wasKept = true;
}
- mNetworkForRequestId.remove(nri.request.requestId);
+ clearNetworkForRequest(nri.request.requestId);
if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
// Went from foreground to background.
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
@@ -4296,7 +4305,8 @@
* and the are the highest scored network available.
* the are keyed off the Requests requestId.
*/
- // TODO: Yikes, this is accessed on multiple threads: add synchronization.
+ // NOTE: Accessed on multiple threads, must be synchronized on itself.
+ @GuardedBy("mNetworkForRequestId")
private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
new SparseArray<NetworkAgentInfo>();
@@ -4326,8 +4336,26 @@
// priority networks like Wi-Fi are active.
private final NetworkRequest mDefaultMobileDataRequest;
+ private NetworkAgentInfo getNetworkForRequest(int requestId) {
+ synchronized (mNetworkForRequestId) {
+ return mNetworkForRequestId.get(requestId);
+ }
+ }
+
+ private void clearNetworkForRequest(int requestId) {
+ synchronized (mNetworkForRequestId) {
+ mNetworkForRequestId.remove(requestId);
+ }
+ }
+
+ private void setNetworkForRequest(int requestId, NetworkAgentInfo nai) {
+ synchronized (mNetworkForRequestId) {
+ mNetworkForRequestId.put(requestId, nai);
+ }
+ }
+
private NetworkAgentInfo getDefaultNetwork() {
- return mNetworkForRequestId.get(mDefaultRequest.requestId);
+ return getNetworkForRequest(mDefaultRequest.requestId);
}
private boolean isDefaultNetwork(NetworkAgentInfo nai) {
@@ -4886,7 +4914,7 @@
// requests or not, and doesn't affect the network's score.
if (nri.request.isListen()) continue;
- final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+ final NetworkAgentInfo currentNetwork = getNetworkForRequest(nri.request.requestId);
final boolean satisfies = newNetwork.satisfies(nri.request);
if (newNetwork == currentNetwork && satisfies) {
if (VDBG) {
@@ -4918,7 +4946,7 @@
if (VDBG) log(" accepting network in place of null");
}
newNetwork.unlingerRequest(nri.request);
- mNetworkForRequestId.put(nri.request.requestId, newNetwork);
+ setNetworkForRequest(nri.request.requestId, newNetwork);
if (!newNetwork.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request);
}
@@ -4952,7 +4980,7 @@
}
newNetwork.removeRequest(nri.request.requestId);
if (currentNetwork == newNetwork) {
- mNetworkForRequestId.remove(nri.request.requestId);
+ clearNetworkForRequest(nri.request.requestId);
sendUpdatedScoreToFactories(nri.request, 0);
} else {
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
@@ -5527,6 +5555,11 @@
return new WakeupMessage(c, h, s, cmd, 0, 0, obj);
}
+ @VisibleForTesting
+ public boolean hasService(String name) {
+ return ServiceManager.checkService(name) != null;
+ }
+
private void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
int newNetid = NETID_UNSET;
int prevNetid = NETID_UNSET;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cbfc747..bffccaf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1690,6 +1690,7 @@
static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
static final int START_USER_SWITCH_FG_MSG = 712;
+ static final int TOP_APP_KILLED_BY_LMK_MSG = 73;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1921,6 +1922,17 @@
dispatchProcessDied(pid, uid);
break;
}
+ case TOP_APP_KILLED_BY_LMK_MSG: {
+ final String appName = (String) msg.obj;
+ final AlertDialog d = new BaseErrorDialog(mUiContext);
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ d.setTitle(mUiContext.getText(R.string.top_app_killed_title));
+ d.setMessage(mUiContext.getString(R.string.top_app_killed_message, appName));
+ d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.close),
+ obtainMessage(DISMISS_DIALOG_UI_MSG, d));
+ d.show();
+ break;
+ }
case DISPATCH_UIDS_CHANGED_UI_MSG: {
dispatchUidsChanged();
} break;
@@ -5430,6 +5442,7 @@
boolean doLowMem = app.instr == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
+ maybeNotifyTopAppKilled(app);
Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: "
+ ProcessList.makeOomAdjString(app.setAdj)
+ ProcessList.makeProcStateString(app.setProcState));
@@ -5463,6 +5476,23 @@
}
}
+ /** Show system error dialog when a top app is killed by LMK */
+ void maybeNotifyTopAppKilled(ProcessRecord app) {
+ if (!shouldNotifyTopAppKilled(app)) {
+ return;
+ }
+
+ Message msg = mHandler.obtainMessage(TOP_APP_KILLED_BY_LMK_MSG);
+ msg.obj = mContext.getPackageManager().getApplicationLabel(app.info);
+ mUiHandler.sendMessage(msg);
+ }
+
+ /** Only show notification when the top app is killed on low ram devices */
+ private boolean shouldNotifyTopAppKilled(ProcessRecord app) {
+ return app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
+ ActivityManager.isLowRamDeviceStatic();
+ }
+
/**
* If a stack trace dump file is configured, dump process stack traces.
* @param clearTraces causes the dump file to be erased prior to the new
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a0817c4..a9ce927 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2246,7 +2246,14 @@
try {
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true;
- result = resumeTopActivityInnerLocked(prev, options);
+ // The contained logic must be synchronized, since we are both changing the visibility
+ // and updating the {@link Configuration}. {@link ActivityRecord#setVisibility} will
+ // ultimately cause the client code to schedule a layout. Since layouts retrieve the
+ // current {@link Configuration}, we must ensure that the below code updates it before
+ // the layout can occur.
+ synchronized (mWindowManager.getWindowManagerLock()) {
+ result = resumeTopActivityInnerLocked(prev, options);
+ }
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 11d0470..3c1f2d4 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -461,6 +461,8 @@
// Forced device usage for communications
private int mForcedUseForComm;
+ private int mForcedUseForCommExt; // External state returned by getters: always consistent
+ // with requests by setters
// List of binder death handlers for setMode() client processes.
// The last process to have called setMode() is at the top of the list.
@@ -2890,13 +2892,14 @@
mForcedUseForComm = AudioSystem.FORCE_NONE;
}
+ mForcedUseForCommExt = mForcedUseForComm;
sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
}
/** @see AudioManager#isSpeakerphoneOn() */
public boolean isSpeakerphoneOn() {
- return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
+ return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
}
/** @see AudioManager#setBluetoothScoOn(boolean) */
@@ -2904,6 +2907,13 @@
if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
return;
}
+
+ // Only enable calls from system components
+ if (Binder.getCallingUid() >= FIRST_APPLICATION_UID) {
+ mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
+ return;
+ }
+
// for logging only
final String eventSource = new StringBuilder("setBluetoothScoOn(").append(on)
.append(") from u/pid:").append(Binder.getCallingUid()).append("/")
@@ -2913,11 +2923,21 @@
public void setBluetoothScoOnInt(boolean on, String eventSource) {
if (on) {
+ // do not accept SCO ON if SCO audio is not connected
+ synchronized(mScoClients) {
+ if ((mBluetoothHeadset != null) &&
+ (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
+ mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
+ return;
+ }
+ }
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
} else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
mForcedUseForComm = AudioSystem.FORCE_NONE;
}
-
+ mForcedUseForCommExt = mForcedUseForComm;
+ AudioSystem.setParameters("BT_SCO="+ (on ? "on" : "off"));
sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
@@ -2926,7 +2946,7 @@
/** @see AudioManager#isBluetoothScoOn() */
public boolean isBluetoothScoOn() {
- return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
+ return (mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO);
}
/** @see AudioManager#setBluetoothA2dpOn(boolean) */
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 14d9afb..a1a0106 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -376,7 +376,7 @@
}
public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
- return new SyntheticPasswordManager(storage, getUserManager());
+ return new SyntheticPasswordManager(getContext(), storage, getUserManager());
}
public int binderGetCallingUid() {
@@ -763,7 +763,8 @@
private void migrateOldDataAfterSystemReady() {
try {
// Migrate the FRP credential to the persistent data block
- if (LockPatternUtils.frpCredentialEnabled() && !getBoolean("migrated_frp", false, 0)) {
+ if (LockPatternUtils.frpCredentialEnabled(mContext)
+ && !getBoolean("migrated_frp", false, 0)) {
migrateFrpCredential();
setBoolean("migrated_frp", true, 0);
Slog.i(TAG, "Migrated migrated_frp.");
@@ -784,7 +785,7 @@
return;
}
for (UserInfo userInfo : mUserManager.getUsers()) {
- if (userOwnsFrpCredential(userInfo) && isUserSecure(userInfo.id)) {
+ if (userOwnsFrpCredential(mContext, userInfo) && isUserSecure(userInfo.id)) {
synchronized (mSpManager) {
if (isSyntheticPasswordBasedCredentialLocked(userInfo.id)) {
int actualQuality = (int) getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
@@ -2504,7 +2505,7 @@
}
public void onSystemReady() {
- if (frpCredentialEnabled()) {
+ if (frpCredentialEnabled(mContext)) {
updateRegistration();
} else {
// If we don't intend to use frpCredentials and we're not provisioned yet, send
@@ -2533,7 +2534,7 @@
private void clearFrpCredentialIfOwnerNotSecure() {
List<UserInfo> users = mUserManager.getUsers();
for (UserInfo user : users) {
- if (userOwnsFrpCredential(user)) {
+ if (userOwnsFrpCredential(mContext, user)) {
if (!isUserSecure(user.id)) {
mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
0, null);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 542b929..c9c9329 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -27,6 +27,7 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
import android.os.DeadObjectException;
@@ -74,7 +75,10 @@
}
public void systemReady() {
- mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+ final PackageManager pm = mContext.getPackageManager();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+ }
}
private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 33a9a99..9440f17 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
+import android.content.Context;
import android.content.pm.UserInfo;
import android.hardware.weaver.V1_0.IWeaver;
import android.hardware.weaver.V1_0.WeaverConfig;
@@ -255,13 +256,16 @@
byte[] aggregatedSecret;
}
+ private final Context mContext;
private LockSettingsStorage mStorage;
private IWeaver mWeaver;
private WeaverConfig mWeaverConfig;
private final UserManager mUserManager;
- public SyntheticPasswordManager(LockSettingsStorage storage, UserManager userManager) {
+ public SyntheticPasswordManager(Context context, LockSettingsStorage storage,
+ UserManager userManager) {
+ mContext = context;
mStorage = storage;
mUserManager = userManager;
}
@@ -645,7 +649,7 @@
public void migrateFrpPasswordLocked(long handle, UserInfo userInfo, int requestedQuality) {
if (mStorage.getPersistentDataBlock() != null
- && LockPatternUtils.userOwnsFrpCredential(userInfo)) {
+ && LockPatternUtils.userOwnsFrpCredential(mContext, userInfo)) {
PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle,
userInfo.id));
if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
@@ -662,7 +666,8 @@
private void synchronizeFrpPassword(PasswordData pwd,
int requestedQuality, int userId) {
if (mStorage.getPersistentDataBlock() != null
- && LockPatternUtils.userOwnsFrpCredential(mUserManager.getUserInfo(userId))) {
+ && LockPatternUtils.userOwnsFrpCredential(mContext,
+ mUserManager.getUserInfo(userId))) {
if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP, userId, requestedQuality,
pwd.toBytes());
@@ -675,7 +680,8 @@
private void synchronizeWeaverFrpPassword(PasswordData pwd, int requestedQuality, int userId,
int weaverSlot) {
if (mStorage.getPersistentDataBlock() != null
- && LockPatternUtils.userOwnsFrpCredential(mUserManager.getUserInfo(userId))) {
+ && LockPatternUtils.userOwnsFrpCredential(mContext,
+ mUserManager.getUserInfo(userId))) {
if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, weaverSlot,
requestedQuality, pwd.toBytes());
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 3795b7f..1cfd5f0 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -271,14 +271,6 @@
// Binder call
@Override
- public boolean isGlobalBluetoothA2doOn() {
- synchronized (mLock) {
- return mGlobalBluetoothA2dpOn;
- }
- }
-
- // Binder call
- @Override
public void setDiscoveryRequest(IMediaRouterClient client,
int routeTypes, boolean activeScan) {
if (client == null) {
@@ -383,7 +375,7 @@
synchronized (mLock) {
a2dpOn = mGlobalBluetoothA2dpOn;
}
- Slog.v(TAG, "restoreBluetoothA2dp( " + a2dpOn + ")");
+ Slog.v(TAG, "restoreBluetoothA2dp(" + a2dpOn + ")");
mAudioService.setBluetoothA2dpOn(a2dpOn);
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn.");
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 92b360b..4e92d10 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,8 +16,10 @@
package com.android.server.notification;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -1143,6 +1145,12 @@
}
@VisibleForTesting
+ NotificationRecord getNotificationRecord(String key) {
+ return mNotificationsByKey.get(key);
+ }
+
+
+ @VisibleForTesting
void setSystemReady(boolean systemReady) {
mSystemReady = systemReady;
}
@@ -1217,7 +1225,7 @@
mUsageStats = usageStats;
mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
mRankingHelper = new RankingHelper(getContext(),
- getContext().getPackageManager(),
+ mPackageManagerClient,
mRankingHandler,
mUsageStats,
extractorNames);
@@ -1270,13 +1278,11 @@
R.array.config_notificationFallbackVibePattern,
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
-
mInCallNotificationUri = Uri.parse("file://" +
resources.getString(R.string.config_inCallNotificationSound));
mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
- .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
.build();
mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
@@ -1477,7 +1483,7 @@
}
}
}
- mRankingHelper.updateNotificationChannel(pkg, uid, channel);
+ mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
if (!fromListener) {
final NotificationChannel modifiedChannel =
@@ -3485,6 +3491,21 @@
user, null, System.currentTimeMillis());
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
+ if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
+ && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
+ && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
+ // Increase the importance of foreground service notifications unless the user had an
+ // opinion otherwise
+ if (TextUtils.isEmpty(channelId)
+ || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
+ r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
+ } else {
+ channel.setImportance(IMPORTANCE_LOW);
+ mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
+ r.updateNotificationChannel(channel);
+ }
+ }
+
if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
r.sbn.getOverrideGroupKey() != null)) {
return;
@@ -3996,19 +4017,19 @@
if (mSystemReady && mAudioManager != null) {
Uri soundUri = record.getSound();
hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
-
long[] vibration = record.getVibration();
// Demote sound to vibration if vibration missing & phone in vibration mode.
if (vibration == null
&& hasValidSound
&& (mAudioManager.getRingerModeInternal()
- == AudioManager.RINGER_MODE_VIBRATE)) {
+ == AudioManager.RINGER_MODE_VIBRATE)
+ && mAudioManager.getStreamVolume(
+ AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
vibration = mFallbackVibrationPattern;
}
hasValidVibrate = vibration != null;
boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
-
if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
if (DBG) Slog.v(TAG, "Interrupting!");
if (hasValidSound) {
@@ -4105,8 +4126,9 @@
boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
// do not play notifications if there is a user of exclusive audio focus
// or the device is in vibrate mode
- if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
- != AudioManager.RINGER_MODE_VIBRATE) {
+ if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal()
+ != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume(
+ AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
final long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 36da04d..332ab6d 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -38,7 +38,7 @@
int uid, boolean includeDeleted);
void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
boolean fromTargetApp);
- void updateNotificationChannel(String pkg, int uid, NotificationChannel channel);
+ void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, boolean fromUser);
NotificationChannel getNotificationChannel(String pkg, int uid, String channelId, boolean includeDeleted);
void deleteNotificationChannel(String pkg, int uid, String channelId);
void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index f193a19..9db4584 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -589,7 +589,8 @@
}
@Override
- public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel) {
+ public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel,
+ boolean fromUser) {
Preconditions.checkNotNull(updatedChannel);
Preconditions.checkNotNull(updatedChannel.getId());
Record r = getOrCreateRecord(pkg, uid);
@@ -603,7 +604,11 @@
if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
updatedChannel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
}
- lockFieldsForUpdate(channel, updatedChannel);
+ updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
+ updatedChannel.lockFields(channel.getUserLockedFields());
+ if (fromUser) {
+ lockFieldsForUpdate(channel, updatedChannel);
+ }
r.channels.put(updatedChannel.getId(), updatedChannel);
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(updatedChannel.getId())) {
@@ -828,8 +833,6 @@
@VisibleForTesting
void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
- update.unlockFields(update.getUserLockedFields());
- update.lockFields(original.getUserLockedFields());
if (original.canBypassDnd() != update.canBypassDnd()) {
update.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4fafe34..e254196 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -425,7 +425,7 @@
}
if (useInfo.isUsedByOtherApps(path)) {
- pw.println("used be other apps: " + useInfo.getLoadingPackages(path));
+ pw.println("used by other apps: " + useInfo.getLoadingPackages(path));
}
Map<String, PackageDexUsage.DexUseInfo> dexUseInfoMap = useInfo.getDexUseInfoMap();
@@ -441,7 +441,7 @@
// TODO(calin): get the status of the oat file (needs installd call)
pw.println("class loader context: " + dexUseInfo.getClassLoaderContext());
if (dexUseInfo.isUsedByOtherApps()) {
- pw.println("used be other apps: " + dexUseInfo.getLoadingPackages());
+ pw.println("used by other apps: " + dexUseInfo.getLoadingPackages());
}
pw.decreaseIndent();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ea1c029..224791b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3312,6 +3312,24 @@
removeCodePathLI(dstCodePath);
return null;
}
+
+ // If we have a profile for a compressed APK, copy it to the reference location.
+ // Since the package is the stub one, remove the stub suffix to get the normal package and
+ // APK name.
+ File profileFile = new File(getPrebuildProfilePath(pkg).replace(STUB_SUFFIX, ""));
+ if (profileFile.exists()) {
+ try {
+ // We could also do this lazily before calling dexopt in
+ // PackageDexOptimizer to prevent this happening on first boot. The issue
+ // is that we don't have a good way to say "do this only once".
+ if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
+ pkg.applicationInfo.uid, pkg.packageName)) {
+ Log.e(TAG, "decompressPackage failed to copy system profile!");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e);
+ }
+ }
return dstCodePath;
}
@@ -9723,7 +9741,7 @@
* and {@code numberOfPackagesFailed}.
*/
private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
- String compilerFilter, boolean bootComplete) {
+ final String compilerFilter, boolean bootComplete) {
int numberOfPackagesVisited = 0;
int numberOfPackagesOptimized = 0;
@@ -9734,6 +9752,8 @@
for (PackageParser.Package pkg : pkgs) {
numberOfPackagesVisited++;
+ boolean useProfileForDexopt = false;
+
if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) {
// Copy over initial preopt profiles since we won't get any JIT samples for methods
// that are already compiled.
@@ -9747,11 +9767,30 @@
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
pkg.applicationInfo.uid, pkg.packageName)) {
Log.e(TAG, "Installer failed to copy system profile!");
+ } else {
+ // Disabled as this causes speed-profile compilation during first boot
+ // even if things are already compiled.
+ // useProfileForDexopt = true;
}
} catch (Exception e) {
Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ",
e);
}
+ } else {
+ PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+ // Handle compressed APKs in this path. Only do this for stubs with profiles to
+ // minimize the number off apps being speed-profile compiled during first boot.
+ // The other paths will not change the filter.
+ if (disabledPs != null && disabledPs.pkg.isStub) {
+ // The package is the stub one, remove the stub suffix to get the normal
+ // package and APK names.
+ String systemProfilePath =
+ getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, "");
+ File systemProfile = new File(systemProfilePath);
+ // Use the profile for compilation if there exists one for the same package
+ // in the system partition.
+ useProfileForDexopt = systemProfile.exists();
+ }
}
}
@@ -9780,17 +9819,13 @@
}
}
- // If the OTA updates a system app which was previously preopted to a non-preopted state
- // the app might end up being verified at runtime. That's because by default the apps
- // are verify-profile but for preopted apps there's no profile.
- // Do a hacky check to ensure that if we have no profiles (a reasonable indication
- // that before the OTA the app was preopted) the app gets compiled with a non-profile
- // filter (by default 'quicken').
- // Note that at this stage unused apps are already filtered.
- if (isSystemApp(pkg) &&
- DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
- !Environment.getReferenceProfile(pkg.packageName).exists()) {
- compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter);
+ String pkgCompilerFilter = compilerFilter;
+ if (useProfileForDexopt) {
+ // Use background dexopt mode to try and use the profile. Note that this does not
+ // guarantee usage of the profile.
+ pkgCompilerFilter =
+ PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+ PackageManagerService.REASON_BACKGROUND_DEXOPT);
}
// checkProfiles is false to avoid merging profiles during boot which
@@ -9801,7 +9836,7 @@
int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0;
int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
pkg.packageName,
- compilerFilter,
+ pkgCompilerFilter,
dexoptFlags));
switch (primaryDexOptStaus) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index bc531c3..f79f0e8 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2623,18 +2623,15 @@
attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
}
- if (ActivityManager.isHighEndGfx()) {
- if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
- attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- }
- final boolean forceWindowDrawsStatusBarBackground =
- (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND)
- != 0;
- if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
- || forceWindowDrawsStatusBarBackground
- && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT) {
- attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- }
+ if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+ attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ }
+ final boolean forceWindowDrawsStatusBarBackground =
+ (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
+ if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
+ || forceWindowDrawsStatusBarBackground
+ && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT) {
+ attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index be44607..f84b20c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -120,7 +120,7 @@
implements Watchdog.Monitor {
private static final String TAG = "PowerManagerService";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final boolean DEBUG_SPEW = DEBUG && true;
// Message: Sent when a user activity timeout occurs to update the power state.
diff --git a/services/core/java/com/android/server/utils/ManagedApplicationService.java b/services/core/java/com/android/server/utils/ManagedApplicationService.java
index 0f251fd..1ea7058 100644
--- a/services/core/java/com/android/server/utils/ManagedApplicationService.java
+++ b/services/core/java/com/android/server/utils/ManagedApplicationService.java
@@ -44,6 +44,7 @@
private final int mClientLabel;
private final String mSettingsAction;
private final BinderChecker mChecker;
+ private final boolean mIsImportant;
private final DeathRecipient mDeathRecipient = new DeathRecipient() {
@Override
@@ -64,13 +65,14 @@
private ManagedApplicationService(final Context context, final ComponentName component,
final int userId, int clientLabel, String settingsAction,
- BinderChecker binderChecker) {
+ BinderChecker binderChecker, boolean isImportant) {
mContext = context;
mComponent = component;
mUserId = userId;
mClientLabel = clientLabel;
mSettingsAction = settingsAction;
mChecker = binderChecker;
+ mIsImportant = isImportant;
}
/**
@@ -99,13 +101,15 @@
* @param settingsAction an action that can be used to open the Settings UI to enable/disable
* binding to these services.
* @param binderChecker an interface used to validate the returned binder object.
+ * @param isImportant bind the user service with BIND_IMPORTANT.
* @return a ManagedApplicationService instance.
*/
public static ManagedApplicationService build(@NonNull final Context context,
@NonNull final ComponentName component, final int userId, @NonNull int clientLabel,
- @NonNull String settingsAction, @NonNull BinderChecker binderChecker) {
+ @NonNull String settingsAction, @NonNull BinderChecker binderChecker,
+ boolean isImportant) {
return new ManagedApplicationService(context, component, userId, clientLabel,
- settingsAction, binderChecker);
+ settingsAction, binderChecker, isImportant);
}
/**
@@ -248,9 +252,12 @@
mPendingConnection = serviceConnection;
+ int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+ if (mIsImportant) {
+ flags |= Context.BIND_IMPORTANT;
+ }
try {
- if (!mContext.bindServiceAsUser(intent, serviceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ if (!mContext.bindServiceAsUser(intent, serviceConnection, flags,
new UserHandle(mUserId))) {
Slog.w(TAG, "Unable to bind service: " + intent);
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 1f0b2f0..830ebda 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -1026,7 +1026,7 @@
@NonNull ComponentName component, int userId) {
return ManagedApplicationService.build(context, component, userId,
R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS,
- sBinderChecker);
+ sBinderChecker, /*isImportant*/true);
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1ac0019..f9d10ad 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2186,8 +2186,18 @@
// and needs process it before handling the corresponding window frame. the variable
// {@code mergedConfiguration} is an out parameter that will be passed back to the
// client over IPC and checked there.
- win.getMergedConfiguration(mergedConfiguration);
- win.setReportedConfiguration(mergedConfiguration);
+ // Note: in the cases where the window is tied to an activity, we should not send a
+ // configuration update when the window has requested to be hidden. Doing so can lead
+ // to the client erroneously accepting a configuration that would have otherwise caused
+ // an activity restart. We instead hand back the last reported
+ // {@link MergedConfiguration}.
+ if (win.mAppToken == null || !win.mAppToken.isClientHidden()) {
+ win.getMergedConfiguration(mergedConfiguration);
+ } else {
+ win.getLastReportedMergedConfiguration(mergedConfiguration);
+ }
+
+ win.setLastReportedMergedConfiguration(mergedConfiguration);
outFrame.set(win.mCompatFrame);
outOverscanInsets.set(win.mOverscanInsets);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 28dba73..77a8fec 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -243,7 +243,7 @@
* We'll send configuration to client only if it is different from the last applied one and
* client won't perform unnecessary updates.
*/
- private final Configuration mLastReportedConfiguration = new Configuration();
+ private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration();
/**
* Actual position of the surface shown on-screen (may be modified by animation). These are
@@ -1241,7 +1241,7 @@
// this is not necessarily what the client has processed yet. Find a
// better indicator consistent with the client.
return (mOrientationChanging || (isVisible()
- && getConfiguration().orientation != mLastReportedConfiguration.orientation))
+ && getConfiguration().orientation != getLastReportedConfiguration().orientation))
&& !mSeamlesslyRotated
&& !mOrientationChangeTimedOut;
}
@@ -1769,7 +1769,7 @@
/** Returns true if last applied config was not yet requested by client. */
boolean isConfigChanged() {
- return !mLastReportedConfiguration.equals(getConfiguration());
+ return !getLastReportedConfiguration().equals(getConfiguration());
}
void onWindowReplacementTimeout() {
@@ -2336,8 +2336,16 @@
outConfiguration.setConfiguration(globalConfig, overrideConfig);
}
- void setReportedConfiguration(MergedConfiguration config) {
- mLastReportedConfiguration.setTo(config.getMergedConfiguration());
+ void setLastReportedMergedConfiguration(MergedConfiguration config) {
+ mLastReportedConfiguration.setTo(config);
+ }
+
+ void getLastReportedMergedConfiguration(MergedConfiguration config) {
+ config.setTo(mLastReportedConfiguration);
+ }
+
+ private Configuration getLastReportedConfiguration() {
+ return mLastReportedConfiguration.getMergedConfiguration();
}
void adjustStartingWindowFlags() {
@@ -3127,7 +3135,7 @@
new MergedConfiguration(mService.mRoot.getConfiguration(),
getMergedOverrideConfiguration());
- setReportedConfiguration(mergedConfiguration);
+ setLastReportedMergedConfiguration(mergedConfiguration);
if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
@@ -3494,7 +3502,7 @@
}
pw.print(prefix); pw.print("mFullConfiguration="); pw.println(getConfiguration());
pw.print(prefix); pw.print("mLastReportedConfiguration=");
- pw.println(mLastReportedConfiguration);
+ pw.println(getLastReportedConfiguration());
}
pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
@@ -3555,7 +3563,7 @@
pw.print(prefix); pw.print("mOrientationChanging=");
pw.print(mOrientationChanging);
pw.print(" configOrientationChanging=");
- pw.print(mLastReportedConfiguration.orientation
+ pw.print(getLastReportedConfiguration().orientation
!= getConfiguration().orientation);
pw.print(" mAppFreezing="); pw.print(mAppFreezing);
pw.print(" mTurnOnScreen="); pw.print(mTurnOnScreen);
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 529ac3a..9fa1d68 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -558,6 +558,7 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
mService.buzzBeepBlinkLocked(r);
@@ -568,6 +569,22 @@
}
@Test
+ public void testNoDemoteSoundToVibrateIfNonNotificationStream() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ assertTrue(r.getSound() != null);
+ assertNull(r.getVibration());
+
+ // the phone is quiet
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(1);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverVibrate();
+ verifyBeepLooped();
+ }
+
+ @Test
public void testDemoteSoundToVibrate() throws Exception {
NotificationRecord r = getBeepyNotification();
assertTrue(r.getSound() != null);
@@ -575,6 +592,7 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
mService.buzzBeepBlinkLocked(r);
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 04b42f1..7ea42da 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -16,12 +16,15 @@
package com.android.server.notification;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -56,6 +59,7 @@
import android.graphics.Color;
import android.media.AudioManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings.Secure;
@@ -241,6 +245,7 @@
nb.build(), new UserHandle(mUid), null, 0);
return new NotificationRecord(mContext, sbn, channel);
}
+
private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
return generateNotificationRecord(channel, null);
}
@@ -342,7 +347,7 @@
// Recreating the channel doesn't throw, but ignores importance.
final NotificationChannel dupeChannel =
- new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id", "name", IMPORTANCE_HIGH);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(dupeChannel)));
final NotificationChannel createdChannel =
@@ -378,7 +383,7 @@
// The user modifies importance directly, can no longer be changed by the app.
final NotificationChannel updatedChannel =
- new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id", "name", IMPORTANCE_HIGH);
mBinderService.updateNotificationChannelForPackage(PKG, mUid, updatedChannel);
// Recreating with a lower importance leaves channel unchanged.
@@ -388,7 +393,7 @@
new ParceledListSlice(Arrays.asList(dupeChannel)));
final NotificationChannel createdChannel =
mBinderService.getNotificationChannel(PKG, "id");
- assertEquals(NotificationManager.IMPORTANCE_HIGH, createdChannel.getImportance());
+ assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance());
}
@Test
@@ -397,7 +402,7 @@
final NotificationChannel channel1 =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
final NotificationChannel channel2 =
- new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id", "name", IMPORTANCE_HIGH);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel1, channel2)));
final NotificationChannel createdChannel =
@@ -410,7 +415,7 @@
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true);
NotificationChannel channel = new NotificationChannel("id", "name",
- NotificationManager.IMPORTANCE_HIGH);
+ IMPORTANCE_HIGH);
NotificationRecord r = generateNotificationRecord(channel);
assertTrue(mNotificationManagerService.isBlocked(r, mUsageStats));
verify(mUsageStats, times(1)).registerSuspendedByAdmin(eq(r));
@@ -421,11 +426,68 @@
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
NotificationChannel channel = new NotificationChannel("id", "name",
- NotificationManager.IMPORTANCE_HIGH);
- channel.setImportance(IMPORTANCE_NONE);
+ NotificationManager.IMPORTANCE_NONE);
NotificationRecord r = generateNotificationRecord(channel);
assertTrue(mNotificationManagerService.isBlocked(r, mUsageStats));
verify(mUsageStats, times(1)).registerBlocked(eq(r));
+
+ mBinderService.createNotificationChannels(
+ PKG, new ParceledListSlice(Arrays.asList(channel)));
+ final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ waitForIdle();
+ assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+ }
+
+ @Test
+ public void testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()
+ throws Exception {
+ when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+
+ NotificationChannel channel = new NotificationChannel("blocked", "name",
+ NotificationManager.IMPORTANCE_NONE);
+ mBinderService.createNotificationChannels(
+ PKG, new ParceledListSlice(Arrays.asList(channel)));
+
+ final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
+ sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ waitForIdle();
+ assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+ assertEquals(IMPORTANCE_LOW,
+ mNotificationManagerService.getNotificationRecord(sbn.getKey()).getImportance());
+ assertEquals(IMPORTANCE_LOW,
+ mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+ }
+
+ @Test
+ public void testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()
+ throws Exception {
+ when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+
+ NotificationChannel channel =
+ new NotificationChannel("blockedbyuser", "name", IMPORTANCE_HIGH);
+ mBinderService.createNotificationChannels(
+ PKG, new ParceledListSlice(Arrays.asList(channel)));
+
+ NotificationChannel update =
+ new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
+ mBinderService.updateNotificationChannelForPackage(PKG, mUid, update);
+ waitForIdle();
+ assertEquals(IMPORTANCE_NONE,
+ mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+
+ final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
+ sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ waitForIdle();
+ assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+ assertNull(mNotificationManagerService.getNotificationRecord(sbn.getKey()));
+ assertEquals(IMPORTANCE_NONE,
+ mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
}
@Test
@@ -442,6 +504,21 @@
}
@Test
+ public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception {
+ when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+
+ mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
+
+ final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+ sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ waitForIdle();
+ assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+ assertNull(mNotificationManagerService.getNotificationRecord(sbn.getKey()));
+ }
+
+ @Test
public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
@@ -798,7 +875,7 @@
mNotificationManagerService.setRankingHelper(mRankingHelper);
when(mRankingHelper.getNotificationChannel(
anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn(
- new NotificationChannel("foo", "foo", NotificationManager.IMPORTANCE_HIGH));
+ new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
@@ -927,7 +1004,8 @@
mBinderService.updateNotificationChannelFromPrivilegedListener(
null, PKG, Process.myUserHandle(), mTestNotificationChannel);
- verify(mRankingHelper, times(1)).updateNotificationChannel(anyString(), anyInt(), any());
+ verify(mRankingHelper, times(1)).updateNotificationChannel(
+ anyString(), anyInt(), any(), anyBoolean());
verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
eq(Process.myUserHandle()), eq(mTestNotificationChannel),
@@ -948,7 +1026,8 @@
// pass
}
- verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any());
+ verify(mRankingHelper, never()).updateNotificationChannel(
+ anyString(), anyInt(), any(), anyBoolean());
verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
eq(Process.myUserHandle()), eq(mTestNotificationChannel),
@@ -974,7 +1053,8 @@
// pass
}
- verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any());
+ verify(mRankingHelper, never()).updateNotificationChannel(
+ anyString(), anyInt(), any(), anyBoolean());
verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
eq(Process.myUserHandle()), eq(mTestNotificationChannel),
@@ -1345,7 +1425,8 @@
@Test
public void testOnlyAutogroupIfGroupChanged_groupChanged_autogroups()
throws Exception {
- NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "group", false);
+ NotificationRecord r =
+ generateNotificationRecord(mTestNotificationChannel, 0, "group", false);
mNotificationManagerService.addNotification(r);
r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
@@ -1425,12 +1506,16 @@
// Same notifications are enqueued as posted, everything counts b/c id and tag don't match
int userId = new UserHandle(mUid).getIdentifier();
- assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, null));
- assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag2"));
- assertEquals(2, mNotificationManagerService.getNotificationCountLocked("a", userId, 0, "banana"));
+ assertEquals(40,
+ mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, null));
+ assertEquals(40,
+ mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag2"));
+ assertEquals(2,
+ mNotificationManagerService.getNotificationCountLocked("a", userId, 0, "banana"));
// exclude a known notification - it's excluded from only the posted list, not enqueued
- assertEquals(39, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag"));
+ assertEquals(39,
+ mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag"));
}
@Test
@@ -1560,4 +1645,51 @@
verify(mZenModeHelper, times(1)).updateDefaultZenRules();
}
+
+ @Test
+ public void testBumpFGImportance_noChannelChangePreOApp() throws Exception {
+ String preOPkg = "preO";
+ int preOUid = 145;
+ final ApplicationInfo legacy = new ApplicationInfo();
+ legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+ when(mPackageManagerClient.getApplicationInfoAsUser(eq(preOPkg), anyInt(), anyInt()))
+ .thenReturn(legacy);
+ when(mPackageManagerClient.getPackageUidAsUser(eq(preOPkg), anyInt())).thenReturn(preOUid);
+ getContext().setMockPackageManager(mPackageManagerClient);
+
+ Notification.Builder nb = new Notification.Builder(mContext,
+ NotificationChannel.DEFAULT_CHANNEL_ID)
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .setPriority(Notification.PRIORITY_MIN);
+
+ StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
+ 0, nb.build(), new UserHandle(preOUid), null, 0);
+
+ mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ waitForIdle();
+ assertEquals(IMPORTANCE_LOW,
+ mNotificationManagerService.getNotificationRecord(sbn.getKey()).getImportance());
+
+ nb = new Notification.Builder(mContext)
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .setPriority(Notification.PRIORITY_MIN);
+
+ sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
+ 0, nb.build(), new UserHandle(preOUid), null, 0);
+
+ mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ waitForIdle();
+ assertEquals(IMPORTANCE_LOW,
+ mNotificationManagerService.getNotificationRecord(sbn.getKey()).getImportance());
+
+ NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
+ preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
+ assertEquals(IMPORTANCE_UNSPECIFIED, defaultChannel.getImportance());
+ }
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 65bf330..61d999a 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -484,7 +484,7 @@
final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
NotificationChannel.DEFAULT_CHANNEL_ID, false);
defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
+ mHelper.updateNotificationChannel(PKG, UID, defaultChannel, true);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
NotificationChannel.DEFAULT_CHANNEL_ID);
@@ -633,7 +633,7 @@
channel2.setBypassDnd(false);
channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
- mHelper.updateNotificationChannel(PKG, UID, channel2);
+ mHelper.updateNotificationChannel(PKG, UID, channel2, true);
// all fields should be changed
assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel.getId(), false));
@@ -657,7 +657,7 @@
defaultChannel.setBypassDnd(true);
defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
- mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
+ mHelper.updateNotificationChannel(PKG, UID, defaultChannel, true);
// ensure app level fields are changed
assertFalse(mHelper.canShowBadge(PKG, UID));
@@ -681,7 +681,7 @@
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
- mHelper.updateNotificationChannel(PKG, UID, channel);
+ mHelper.updateNotificationChannel(PKG, UID, channel, true);
// ensure app level fields are not changed
assertTrue(mHelper.canShowBadge(PKG, UID));
@@ -772,14 +772,14 @@
update1.setSound(new Uri.Builder().scheme("test").build(),
new AudioAttributes.Builder().build());
update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); // should be ignored
- mHelper.updateNotificationChannel(PKG, UID, update1);
+ mHelper.updateNotificationChannel(PKG, UID, update1, true);
assertEquals(NotificationChannel.USER_LOCKED_SOUND,
mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
.getUserLockedFields());
NotificationChannel update2 = getChannel();
update2.enableVibration(true);
- mHelper.updateNotificationChannel(PKG, UID, update2);
+ mHelper.updateNotificationChannel(PKG, UID, update2, true);
assertEquals(NotificationChannel.USER_LOCKED_SOUND
| NotificationChannel.USER_LOCKED_VIBRATION,
mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
@@ -792,14 +792,14 @@
final NotificationChannel update1 = getChannel();
update1.setVibrationPattern(new long[]{7945, 46 ,246});
- mHelper.updateNotificationChannel(PKG, UID, update1);
+ mHelper.updateNotificationChannel(PKG, UID, update1, true);
assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
.getUserLockedFields());
final NotificationChannel update2 = getChannel();
update2.enableLights(true);
- mHelper.updateNotificationChannel(PKG, UID, update2);
+ mHelper.updateNotificationChannel(PKG, UID, update2, true);
assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
| NotificationChannel.USER_LOCKED_LIGHTS,
mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
@@ -812,14 +812,14 @@
final NotificationChannel update1 = getChannel();
update1.setLightColor(Color.GREEN);
- mHelper.updateNotificationChannel(PKG, UID, update1);
+ mHelper.updateNotificationChannel(PKG, UID, update1, true);
assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
.getUserLockedFields());
final NotificationChannel update2 = getChannel();
update2.setImportance(IMPORTANCE_DEFAULT);
- mHelper.updateNotificationChannel(PKG, UID, update2);
+ mHelper.updateNotificationChannel(PKG, UID, update2, true);
assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
| NotificationChannel.USER_LOCKED_IMPORTANCE,
mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
@@ -835,14 +835,14 @@
final NotificationChannel update1 = getChannel();
update1.setBypassDnd(true);
- mHelper.updateNotificationChannel(PKG, UID, update1);
+ mHelper.updateNotificationChannel(PKG, UID, update1, true);
assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
.getUserLockedFields());
final NotificationChannel update2 = getChannel();
update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
- mHelper.updateNotificationChannel(PKG, UID, update2);
+ mHelper.updateNotificationChannel(PKG, UID, update2, true);
assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
| NotificationChannel.USER_LOCKED_VISIBILITY,
mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
@@ -850,7 +850,7 @@
final NotificationChannel update3 = getChannel();
update3.setShowBadge(false);
- mHelper.updateNotificationChannel(PKG, UID, update3);
+ mHelper.updateNotificationChannel(PKG, UID, update3, true);
assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
| NotificationChannel.USER_LOCKED_VISIBILITY
| NotificationChannel.USER_LOCKED_SHOW_BADGE,
@@ -1263,7 +1263,7 @@
mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
channel1.setImportance(IMPORTANCE_LOW);
- mHelper.updateNotificationChannel(PKG, UID, channel1);
+ mHelper.updateNotificationChannel(PKG, UID, channel1, true);
List<NotificationChannelGroup> actual =
mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 13cf9df..7cba280 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -106,7 +106,8 @@
return mService;
}
};
- mSpManager = new MockSyntheticPasswordManager(mStorage, mGateKeeperService, mUserManager);
+ mSpManager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService,
+ mUserManager);
mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage,
mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager,
mSpManager);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
index cf03593..6f68179 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
@@ -15,6 +15,7 @@
*/
package com.android.server.locksettings;
+import android.content.Context;
import android.hardware.weaver.V1_0.IWeaver;
import android.os.RemoteException;
import android.os.UserManager;
@@ -35,9 +36,9 @@
private FakeGateKeeperService mGateKeeper;
private IWeaver mWeaverService;
- public MockSyntheticPasswordManager(LockSettingsStorage storage,
+ public MockSyntheticPasswordManager(Context context, LockSettingsStorage storage,
FakeGateKeeperService gatekeeper, UserManager userManager) {
- super(storage, userManager);
+ super(context, storage, userManager);
mGateKeeper = gatekeeper;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 2c9aa9d..2ad0580 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -58,7 +58,7 @@
final int USER_ID = 10;
final String PASSWORD = "user-password";
final String BADPASSWORD = "bad-password";
- MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mStorage,
+ MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
mGateKeeperService, mUserManager);
AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null,
null, USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 7ff1110..272e451 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -32,6 +32,7 @@
import static android.content.res.Configuration.EMPTY;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
/**
* A collection of static functions that can be referenced by other test packages to provide access
@@ -51,7 +52,10 @@
* Retrieves an instance of a mock {@link WindowManagerService}.
*/
public static WindowManagerService getMockWindowManagerService() {
- return mock(WindowManagerService.class);
+ final WindowManagerService service = mock(WindowManagerService.class);
+ final WindowHashMap windowMap = new WindowHashMap();
+ when(service.getWindowManagerLock()).thenReturn(windowMap);
+ return service;
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2c02869..011d76b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -106,8 +106,6 @@
public static final String MODEM_ACTIVITY_RESULT_KEY =
BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY;
- private static ITelephonyRegistry sRegistry;
-
/**
* The allowed states of Wi-Fi calling.
*
@@ -178,11 +176,6 @@
mContext = context;
}
mSubscriptionManager = SubscriptionManager.from(mContext);
-
- if (sRegistry == null) {
- sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
- "telephony.registry"));
- }
}
/** @hide */
@@ -3506,6 +3499,10 @@
return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
}
+ private ITelephonyRegistry getTelephonyRegistry() {
+ return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
+ }
+
//
//
// PhoneStateListener
@@ -3545,12 +3542,16 @@
if (listener.mSubId == null) {
listener.mSubId = mSubId;
}
- sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
- listener.callback, events, notifyNow);
+
+ ITelephonyRegistry registry = getTelephonyRegistry();
+ if (registry != null) {
+ registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
+ listener.callback, events, notifyNow);
+ } else {
+ Rlog.w(TAG, "telephony registry not ready.");
+ }
} catch (RemoteException ex) {
// system process dead
- } catch (NullPointerException ex) {
- // system process dead
}
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 8816d43..6674f20 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -19,6 +19,8 @@
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.getNetworkTypeName;
@@ -781,6 +783,13 @@
return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
}
+ @Override
+ public boolean hasService(String name) {
+ // Currenty, the only relevant service that ConnectivityService checks for is
+ // ETHERNET_SERVICE.
+ return Context.ETHERNET_SERVICE.equals(name);
+ }
+
public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
return mLastCreatedNetworkMonitor;
}
@@ -928,6 +937,13 @@
// will fail. Failing here is much easier to debug.
assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
+ assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS));
+ assertFalse(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
+
+ // Check that TYPE_ETHERNET is supported. Unlike the asserts above, which only validate our
+ // mocks, this assert exercises the ConnectivityService code path that ensures that
+ // TYPE_ETHERNET is supported if the ethernet service is running.
+ assertTrue(mCm.isNetworkSupported(TYPE_ETHERNET));
}
@SmallTest