diff options
95 files changed, 1192 insertions, 594 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index fb72e651cebd..77875354d732 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -834,9 +834,12 @@ public class AppOpsManager { public static final int OP_ACCESS_ACCESSIBILITY = 88; /** @hide Read the device identifiers (IMEI / MEID, IMSI, SIM / Build serial) */ public static final int OP_READ_DEVICE_IDENTIFIERS = 89; + /** @hide Read location metadata from media */ + public static final int OP_ACCESS_MEDIA_LOCATION = 90; + /** @hide */ @UnsupportedAppUsage - public static final int _NUM_OP = 90; + public static final int _NUM_OP = 91; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1107,6 +1110,9 @@ public class AppOpsManager { @TestApi @SystemApi public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage"; + /** @hide Read location metadata from media */ + public static final String OPSTR_ACCESS_MEDIA_LOCATION = "android:access_media_location"; + /** @hide Interact with accessibility. */ @SystemApi public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility"; @@ -1134,6 +1140,7 @@ public class AppOpsManager { // Storage OP_READ_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE, + OP_ACCESS_MEDIA_LOCATION, // Location OP_COARSE_LOCATION, OP_FINE_LOCATION, @@ -1273,6 +1280,7 @@ public class AppOpsManager { OP_LEGACY_STORAGE, // LEGACY_STORAGE OP_ACCESS_ACCESSIBILITY, // ACCESS_ACCESSIBILITY OP_READ_DEVICE_IDENTIFIERS, // READ_DEVICE_IDENTIFIERS + OP_ACCESS_MEDIA_LOCATION, // ACCESS_MEDIA_LOCATION }; /** @@ -1369,6 +1377,7 @@ public class AppOpsManager { OPSTR_LEGACY_STORAGE, OPSTR_ACCESS_ACCESSIBILITY, OPSTR_READ_DEVICE_IDENTIFIERS, + OPSTR_ACCESS_MEDIA_LOCATION, }; /** @@ -1466,6 +1475,7 @@ public class AppOpsManager { "LEGACY_STORAGE", "ACCESS_ACCESSIBILITY", "READ_DEVICE_IDENTIFIERS", + "ACCESS_MEDIA_LOCATION", }; /** @@ -1564,6 +1574,7 @@ public class AppOpsManager { null, // no permission for OP_LEGACY_STORAGE null, // no permission for OP_ACCESS_ACCESSIBILITY null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS + Manifest.permission.ACCESS_MEDIA_LOCATION, }; /** @@ -1662,6 +1673,7 @@ public class AppOpsManager { null, // LEGACY_STORAGE null, // ACCESS_ACCESSIBILITY null, // READ_DEVICE_IDENTIFIERS + null, // ACCESS_MEDIA_LOCATION }; /** @@ -1759,6 +1771,7 @@ public class AppOpsManager { false, // LEGACY_STORAGE false, // ACCESS_ACCESSIBILITY false, // READ_DEVICE_IDENTIFIERS + false, // ACCESS_MEDIA_LOCATION }; /** @@ -1855,6 +1868,7 @@ public class AppOpsManager { AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS + AppOpsManager.MODE_ALLOWED, // ALLOW_MEDIA_LOCATION }; /** @@ -1955,6 +1969,7 @@ public class AppOpsManager { false, // LEGACY_STORAGE false, // ACCESS_ACCESSIBILITY false, // READ_DEVICE_IDENTIFIERS + false, // ACCESS_MEDIA_LOCATION }; /** @@ -2587,7 +2602,7 @@ public class AppOpsManager { * @return The proxy UID. */ public int getProxyUid() { - return (int) findFirstNonNegativeForFlagsInStates(mDurations, + return (int) findFirstNonNegativeForFlagsInStates(mProxyUids, MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL); } @@ -2609,7 +2624,7 @@ public class AppOpsManager { * @return The proxy UID. */ public int getProxyUid(@UidState int uidState, @OpFlags int flags) { - return (int) findFirstNonNegativeForFlagsInStates(mDurations, + return (int) findFirstNonNegativeForFlagsInStates(mProxyUids, uidState, uidState, flags); } @@ -4169,8 +4184,8 @@ public class AppOpsManager { * end UID states. * * @param counts The data array. - * @param beginUidState The beginning UID state (exclusive). - * @param endUidState The end UID state. + * @param beginUidState The beginning UID state (inclusive). + * @param endUidState The end UID state (inclusive). * @param flags The UID flags. * @return The sum. */ @@ -4199,13 +4214,13 @@ public class AppOpsManager { * end UID states. * * @param counts The data array. + * @param beginUidState The beginning UID state (inclusive). + * @param endUidState The end UID state (inclusive). * @param flags The UID flags. - * @param beginUidState The beginning UID state (exclusive). - * @param endUidState The end UID state. * @return The non-negative value or -1. */ private static long findFirstNonNegativeForFlagsInStates(@Nullable LongSparseLongArray counts, - @OpFlags int flags, @UidState int beginUidState, @UidState int endUidState) { + @UidState int beginUidState, @UidState int endUidState, @OpFlags int flags) { if (counts == null) { return -1; } @@ -4231,14 +4246,14 @@ public class AppOpsManager { * end UID states. * * @param counts The data array. + * @param beginUidState The beginning UID state (inclusive). + * @param endUidState The end UID state (inclusive). * @param flags The UID flags. - * @param beginUidState The beginning UID state (exclusive). - * @param endUidState The end UID state. * @return The non-negative value or -1. */ private static @Nullable String findFirstNonNullForFlagsInStates( - @Nullable LongSparseArray<String> counts, @OpFlags int flags, - @UidState int beginUidState, @UidState int endUidState) { + @Nullable LongSparseArray<String> counts, @UidState int beginUidState, + @UidState int endUidState, @OpFlags int flags) { if (counts == null) { return null; } diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index fb78789ba8ad..cfb363a0834c 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -118,6 +118,8 @@ public final class BluetoothPan implements BluetoothProfile { */ public static final int PAN_OPERATION_SUCCESS = 1004; + private final Context mContext; + private BluetoothAdapter mAdapter; private final BluetoothProfileConnector<IBluetoothPan> mProfileConnector = new BluetoothProfileConnector(this, BluetoothProfile.PAN, @@ -136,6 +138,7 @@ public final class BluetoothPan implements BluetoothProfile { @UnsupportedAppUsage /*package*/ BluetoothPan(Context context, ServiceListener listener) { mAdapter = BluetoothAdapter.getDefaultAdapter(); + mContext = context; mProfileConnector.connect(context, listener); } @@ -287,11 +290,12 @@ public final class BluetoothPan implements BluetoothProfile { @UnsupportedAppUsage public void setBluetoothTethering(boolean value) { - if (DBG) log("setBluetoothTethering(" + value + ")"); + String pkgName = mContext.getOpPackageName(); + if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName); final IBluetoothPan service = getService(); if (service != null && isEnabled()) { try { - service.setBluetoothTethering(value); + service.setBluetoothTethering(value, pkgName); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); } diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 9d523633feb6..099dea29eaf7 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -60,9 +60,7 @@ import java.util.Set; * multiple possible matching values (via {@link #addAction}, * {@link #addDataType}, {@link #addDataScheme}, {@link #addDataSchemeSpecificPart}, * {@link #addDataAuthority}, {@link #addDataPath}, and {@link #addCategory}, respectively). - * For actions, the field - * will not be tested if no values have been given (treating it as a wildcard); - * if no data characteristics are specified, however, then the filter will + * For actions, if no data characteristics are specified, then the filter will * only match intents that contain no data. * * <p>The data characteristic is diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index c74daa8eadfc..3933e81c732a 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -519,9 +519,9 @@ public class LauncherApps { * <li>The app is a system app.</li> * <li>The app doesn't request any <a href="/guide/topics/permissions/overview">permissions</a>. * </li> - * <li>The <code><application></code> tag in the app's manifest doesn't contain any child - * elements that represent - * <a href="/guide/components/fundamentals#DeclaringComponents">app components</a>.</li> + * <li>The app doesn't have a <em>launcher activity</em> that is enabled by default. A launcher + * activity has an intent containing the <code>ACTION_MAIN</code> action and the + * <code>CATEGORY_LAUNCHER</code> category.</li> * </ul> * * <p>Additionally, the system hides synthesized activities for some or all apps in the diff --git a/core/java/android/content/pm/PackageList.java b/core/java/android/content/pm/PackageList.java index f78175868860..e3eb2c55a2bb 100644 --- a/core/java/android/content/pm/PackageList.java +++ b/core/java/android/content/pm/PackageList.java @@ -52,6 +52,13 @@ public class PackageList implements PackageListObserver, AutoCloseable { } @Override + public void onPackageChanged(String packageName, int uid) { + if (mWrappedObserver != null) { + mWrappedObserver.onPackageChanged(packageName, uid); + } + } + + @Override public void onPackageRemoved(String packageName, int uid) { if (mWrappedObserver != null) { mWrappedObserver.onPackageRemoved(packageName, uid); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 06ced7c68467..f42228935579 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -2338,6 +2338,12 @@ public class CameraDeviceImpl extends CameraDevice final CaptureCallbackHolder holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId); + if (holder == null) { + Log.e(TAG, String.format("Receive capture error on unknown request ID %d", + requestId)); + return; + } + final CaptureRequest request = holder.getRequest(subsequenceId); Runnable failureDispatch = null; diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 86651060a394..1c50d73c4953 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -276,6 +276,7 @@ public class TextLine { final int runCount = mDirections.getRunCount(); for (int runIndex = 0; runIndex < runCount; runIndex++) { final int runStart = mDirections.getRunStart(runIndex); + if (runStart > mLen) break; final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen); final boolean runIsRtl = mDirections.isRunRtl(runIndex); @@ -360,6 +361,7 @@ public class TextLine { float h = 0; for (int runIndex = 0; runIndex < mDirections.getRunCount(); runIndex++) { final int runStart = mDirections.getRunStart(runIndex); + if (runStart > mLen) break; final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen); final boolean runIsRtl = mDirections.isRunRtl(runIndex); @@ -417,6 +419,7 @@ public class TextLine { float h = 0; for (int runIndex = 0; runIndex < mDirections.getRunCount(); runIndex++) { final int runStart = mDirections.getRunStart(runIndex); + if (runStart > mLen) break; final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen); final boolean runIsRtl = mDirections.isRunRtl(runIndex); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 84665f78c702..c6536bb71cba 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -14431,8 +14431,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); - if (isVisible != oldVisible) { - updateSystemGestureExclusionRects(); + if (!getSystemGestureExclusionRects().isEmpty() && isVisible != oldVisible) { + postUpdateSystemGestureExclusionRects(); } } diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index a3e89c85fcbc..51b0950a7544 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -71,9 +71,9 @@ import java.util.List; * instead of scroll view which offers greater user interface flexibility and * support for the material design scrolling patterns.</p> * - * <p>To learn more about material design patterns for handling scrolling, see - * <a href="https://material.io/guidelines/patterns/scrolling-techniques.html#"> - * Scrolling techniques</a>.</p> + * <p>Material Design offers guidelines on how the appearance of + * <a href="https://material.io/components/">several UI components</a>, including app bars and + * banners, should respond to gestures.</p> * * @attr ref android.R.styleable#ScrollView_fillViewport */ diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 7c52a40d4494..07002d788908 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -796,7 +796,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateElevation(); mAllowUpdateElevation = true; - if (changed && mResizeMode == RESIZE_MODE_DOCKED_DIVIDER) { + if (changed + && (mResizeMode == RESIZE_MODE_DOCKED_DIVIDER + || mDrawLegacyNavigationBarBackground)) { getViewRootImpl().requestInvalidateRootRenderNode(); } } diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 4f0c5ee1af88..eca985d997e1 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -294,7 +294,7 @@ <string name="permgrouprequest_calendar" msgid="289900767793189421">"Dozvoliti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupi vašem kalendaru?"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"šalje i pregleda SMS poruke"</string> - <string name="permgrouprequest_sms" msgid="7168124215838204719">"Dozvoliti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> slanje i pregled SMS poruka?"</string> + <string name="permgrouprequest_sms" msgid="7168124215838204719">"Dozvoliti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da šalje i pregleda SMS poruke?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Pohrana"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"pristupa slikama, medijskim fajlovima i fajlovima na vašem uređaju"</string> <string name="permgrouprequest_storage" msgid="7885942926944299560">"Dozvoliti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupa fotografijama, medijima i fajlovima na vašem uređaju?"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 7b8ef7b57053..6fdc493a4c68 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -282,7 +282,7 @@ <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Zulassen, dass <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> auf deine Kontakte zugreift?"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Standort"</string> <string name="permgroupdesc_location" msgid="1346617465127855033">"auf den Standort deines Geräts zugreifen"</string> - <string name="permgrouprequest_location" msgid="3788275734953323491">"Zulassen, dass <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> den Gerätestandort abruft?"</string> + <string name="permgrouprequest_location" msgid="3788275734953323491">"Zulassen, dass die App <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> den Gerätestandort abruft?"</string> <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"Die App hat nur Zugriff auf den Gerätestandort, solange du sie verwendest"</string> <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"Zulassen, dass <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> <b>ständig</b> auf deinen Standort zugreift?"</string> <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"Die App hat gegenwärtig nur dann Zugriff auf den Gerätestandort, wenn du sie verwendest"</string> @@ -291,7 +291,7 @@ <string name="permgrouprequest_calendar" msgid="289900767793189421">"Zulassen, dass <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> auf deinen Kalender zugreift?"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS senden und abrufen"</string> - <string name="permgrouprequest_sms" msgid="7168124215838204719">"Zulassen, dass <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> SMS sendet und aufruft?"</string> + <string name="permgrouprequest_sms" msgid="7168124215838204719">"Zulassen, dass die App <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> SMS sendet und aufruft?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Speicher"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"auf Fotos, Medien und Dateien auf deinem Gerät zugreifen"</string> <string name="permgrouprequest_storage" msgid="7885942926944299560">"Zulassen, dass <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> auf Fotos, Medien und Dateien auf deinem Gerät zugreift?"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 9b1bdd37258d..15326c8dac74 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -243,7 +243,7 @@ <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Hääletu režiim"</string> <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Heli on VÄLJAS"</string> <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Heli on SEES"</string> - <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lennurežiim"</string> + <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lennukirežiim"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lennurežiim on SEES"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lennurežiim on VÄLJAS"</string> <string name="global_action_settings" msgid="1756531602592545966">"Seaded"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 35d97af3424b..e5c203742343 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -1636,7 +1636,7 @@ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN kode okerra."</string> <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Idatzi 4 eta 8 zenbaki arteko PINa."</string> <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK kodeak 8 zenbaki izan behar ditu."</string> - <string name="kg_invalid_puk" msgid="3638289409676051243">"Idatzi berriro PUK kode zuzena. Hainbat saiakera oker eginez gero, betirako desgaituko da SIMa."</string> + <string name="kg_invalid_puk" msgid="3638289409676051243">"Idatzi berriro PUK kode zuzena. Hainbat saiakera oker eginez gero, betiko desgaituko da SIMa."</string> <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodeak ez datoz bat"</string> <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Eredua marrazteko saiakera gehiegi egin dira"</string> <string name="kg_login_instructions" msgid="1100551261265506448">"Desblokeatzeko, hasi saioa Google kontuarekin."</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 42495f0cc170..6f867cbf953a 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -291,7 +291,7 @@ <string name="permgrouprequest_calendar" msgid="289900767793189421">"به <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> اجازه داده شود به تقویم شما دسترسی پیدا کند؟"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"پیامک"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"ارسال و مشاهده پیامکها"</string> - <string name="permgrouprequest_sms" msgid="7168124215838204719">"به <b><xliff:g id="APP_NAME">%1$s</xliff:g><b> اجازه داده شود پیامکها را ارسال و مشاهده کند؟"</string> + <string name="permgrouprequest_sms" msgid="7168124215838204719">"به «<b><xliff:g id="APP_NAME">%1$s</xliff:g><b>» اجازه داده شود پیامک ارسال و مشاهده کند؟"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"حافظه"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"دسترسی به عکسها، رسانهها و فایلهای روی دستگاهتان"</string> <string name="permgrouprequest_storage" msgid="7885942926944299560">"به برنامه <b><xliff:g id="APP_NAME">%1$s</xliff:g><b> اجازه داده شود به عکسها، رسانه، و فایلهای موجود در دستگاهتان دسترسی داشته باشد؟"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 4f4eacb8afe3..c3f6e402ab98 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -282,7 +282,7 @@ <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Saako <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> yhteystietojesi käyttöoikeuden?"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Sijainti"</string> <string name="permgroupdesc_location" msgid="1346617465127855033">"käyttää laitteen sijaintia"</string> - <string name="permgrouprequest_location" msgid="3788275734953323491">"Saako <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tämän laitteen sijainnin käyttöoikeuden?"</string> + <string name="permgrouprequest_location" msgid="3788275734953323491">"Saako <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> oikeuden nähdä tämän laitteen sijainnin?"</string> <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"Sovellus saa sijainnin käyttöoikeuden vain silloin, kun käytät sovellusta"</string> <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"Saako <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> käyttää laitteen sijaintia <b>aina</b>?"</string> <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"Sovellus saa tällä hetkellä sijainnin käyttöoikeuden vain, jos käytät sovellusta"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 6e3192ef5ef1..44e70d45d93d 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -291,7 +291,7 @@ <string name="permgrouprequest_calendar" msgid="289900767793189421">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'accéder à votre agenda ?"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"envoyer et consulter des SMS"</string> - <string name="permgrouprequest_sms" msgid="7168124215838204719">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'envoyer et d\'afficher des SMS ?"</string> + <string name="permgrouprequest_sms" msgid="7168124215838204719">"Autoriser l\'application <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à envoyer et afficher des SMS ?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Stockage"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"accéder aux photos, contenus multimédias et fichiers sur votre appareil"</string> <string name="permgrouprequest_storage" msgid="7885942926944299560">"Autoriser l\'appli <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder aux photos, contenus multimédias et fichiers sur votre appareil ?"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index e81c3f427fcf..19501f1a8761 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -1091,27 +1091,27 @@ <string name="inputMethod" msgid="1653630062304567879">"Método de introdución de texto"</string> <string name="editTextMenuTitle" msgid="4909135564941815494">"Accións de texto"</string> <string name="email" msgid="4560673117055050403">"Correo electrónico"</string> - <string name="email_desc" msgid="3638665569546416795">"Envía un correo electrónico ao enderezo seleccionado"</string> + <string name="email_desc" msgid="3638665569546416795">"Enviar un correo electrónico ao enderezo seleccionado"</string> <string name="dial" msgid="1253998302767701559">"Chamar"</string> - <string name="dial_desc" msgid="6573723404985517250">"Chama ao número de teléfono seleccionado"</string> + <string name="dial_desc" msgid="6573723404985517250">"Chamar ao número de teléfono seleccionado"</string> <string name="map" msgid="5441053548030107189">"Mapa"</string> - <string name="map_desc" msgid="1836995341943772348">"Localiza o enderezo seleccionado"</string> + <string name="map_desc" msgid="1836995341943772348">"Localizar o enderezo seleccionado"</string> <string name="browse" msgid="1245903488306147205">"Abrir"</string> - <string name="browse_desc" msgid="8220976549618935044">"Abre o URL seleccionado"</string> + <string name="browse_desc" msgid="8220976549618935044">"Abrir o URL seleccionado"</string> <string name="sms" msgid="4560537514610063430">"Enviar SMS"</string> - <string name="sms_desc" msgid="7526588350969638809">"Envía unha mensaxe ao número de teléfono seleccionado"</string> + <string name="sms_desc" msgid="7526588350969638809">"Enviar unha mensaxe ao número de teléfono seleccionado"</string> <string name="add_contact" msgid="7867066569670597203">"Engadir"</string> - <string name="add_contact_desc" msgid="4830217847004590345">"Engade o elemento aos contactos"</string> + <string name="add_contact_desc" msgid="4830217847004590345">"Engadir o elemento aos contactos"</string> <string name="view_calendar" msgid="979609872939597838">"Ver"</string> - <string name="view_calendar_desc" msgid="5828320291870344584">"Consulta a hora seleccionada no calendario"</string> + <string name="view_calendar_desc" msgid="5828320291870344584">"Consultar a hora seleccionada no calendario"</string> <string name="add_calendar_event" msgid="1953664627192056206">"Programar"</string> - <string name="add_calendar_event_desc" msgid="4326891793260687388">"Programa un evento para a data seleccionada"</string> + <string name="add_calendar_event_desc" msgid="4326891793260687388">"Programar un evento para a data seleccionada"</string> <string name="view_flight" msgid="7691640491425680214">"Realizar seguimento"</string> - <string name="view_flight_desc" msgid="3876322502674253506">"Fai un seguimento do voo seleccionado"</string> + <string name="view_flight_desc" msgid="3876322502674253506">"Facer un seguimento do voo seleccionado"</string> <string name="translate" msgid="9218619809342576858">"Traducir"</string> - <string name="translate_desc" msgid="4502367770068777202">"Traduce o texto seleccionado"</string> + <string name="translate_desc" msgid="4502367770068777202">"Traducir o texto seleccionado"</string> <string name="define" msgid="7394820043869954211">"Definir"</string> - <string name="define_desc" msgid="7910883642444919726">"Define o texto seleccionado"</string> + <string name="define_desc" msgid="7910883642444919726">"Definir o texto seleccionado"</string> <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Estase esgotando o espazo de almacenamento"</string> <string name="low_internal_storage_view_text" msgid="6640505817617414371">"É posible que algunhas funcións do sistema non funcionen"</string> <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Non hai almacenamento suficiente para o sistema. Asegúrate de ter un espazo libre de 250 MB e reinicia o dispositivo."</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 7f22d6767dee..7353f3525087 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -282,7 +282,7 @@ <string name="permgrouprequest_contacts" msgid="6032805601881764300">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને તમારા સંપર્કોને ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"સ્થાન"</string> <string name="permgroupdesc_location" msgid="1346617465127855033">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની"</string> - <string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string> + <string name="permgrouprequest_location" msgid="3788275734953323491">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને આ ડિવાઇસના સ્થાનને ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string> <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"જ્યારે તમે ઍપનો ઉપયોગ કરી રહ્યા હશો માત્ર ત્યારે જ ઍપ સ્થાનને ઍક્સેસ કરી શકશે"</string> <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને આ ડિવાઇસનું સ્થાન <b>હંમેશાં</b> ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string> <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"હાલમાં માત્ર જ્યારે તમે ઍપનો ઉપયોગ કરી રહ્યા હશો હોય ત્યારે જ ઍપ સ્થાનને ઍક્સેસ કરી શકશે"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 3f278da959e8..0e3d36c64af5 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1855,8 +1855,8 @@ <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"다운타임"</string> <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"평일 밤"</string> <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"주말"</string> - <string name="zen_mode_default_events_name" msgid="8158334939013085363">"캘린더 일정 중"</string> - <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"수면 중"</string> + <string name="zen_mode_default_events_name" msgid="8158334939013085363">"캘린더 일정"</string> + <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"수면 시간"</string> <string name="muted_by" msgid="5942954724562097128">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>(이)가 일부 소리를 음소거함"</string> <string name="system_error_wipe_data" msgid="6608165524785354962">"사용 중인 기기 내부에 문제가 발생했습니다. 초기화할 때까지 불안정할 수 있습니다."</string> <string name="system_error_manufacturer" msgid="8086872414744210668">"사용 중인 기기 내부에 문제가 발생했습니다. 자세한 내용은 제조업체에 문의하세요."</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 2bcbe13a0774..4b301859a200 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1255,7 +1255,7 @@ <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"ကွန်ရက်အားလုံးကို ကြည့်ရန် တို့ပါ"</string> <string name="wifi_available_action_connect" msgid="2635699628459488788">"ချိတ်ဆက်ရန်"</string> <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"ကွန်ရက်အားလုံး"</string> - <string name="wifi_suggestion_title" msgid="6396033039578436801">"အကြံပြုထားသည့် Wi‑Fi ကွန်ရက်များကို ခွင့်ပြုလိုပါသလား။"</string> + <string name="wifi_suggestion_title" msgid="6396033039578436801">"အကြံပြုထားသည့် Wi‑Fi ကွန်ရက်များ ခွင့်ပြုမလား။"</string> <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> သည် ကွန်ရက်များကို အကြံပြုထားသည်။ စက်သည် အလိုအလျောက် ချိတ်ဆက်နိုင်သည်။"</string> <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"ခွင့်ပြုရန်"</string> <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"မလိုပါ"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 224ea87b4119..f1a68bee429d 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -291,7 +291,7 @@ <string name="permgrouprequest_calendar" msgid="289900767793189421">"Vil du gi <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tilgang til kalenderen din?"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"sende og lese SMS-meldinger"</string> - <string name="permgrouprequest_sms" msgid="7168124215838204719">"Vil du la <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sende og se SMS-meldinger?"</string> + <string name="permgrouprequest_sms" msgid="7168124215838204719">"Vil du la <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sende og se tekstmeldinger?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Lagring"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"åpne bilder, medieinnhold og filer på enheten din"</string> <string name="permgrouprequest_storage" msgid="7885942926944299560">"Vil du gi <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tilgang til bilder, medier og filer på enheten din?"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index b536eb1678bb..baf81428f24d 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1300,7 +1300,7 @@ <string name="wifi_available_action_connect" msgid="2635699628459488788">"Połącz"</string> <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Wszystkie sieci"</string> <string name="wifi_suggestion_title" msgid="6396033039578436801">"Zezwalać na sugerowane sieci Wi‑Fi?"</string> - <string name="wifi_suggestion_content" msgid="5603992011371520746">"Sugerowane sieci: <xliff:g id="NAME">%s</xliff:g>. Urządzenie może połączyć się automatycznie."</string> + <string name="wifi_suggestion_content" msgid="5603992011371520746">"Sugerowane sieci: <xliff:g id="NAME">%s</xliff:g>. Urządzenie może łączyć się automatycznie."</string> <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Zezwól"</string> <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nie, dziękuję"</string> <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi włączy się automatycznie"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index a8be5952718d..8a83b774826e 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1476,7 +1476,7 @@ <string name="submit" msgid="1602335572089911941">"Enviar"</string> <string name="car_mode_disable_notification_title" msgid="5704265646471239078">"O app para carro está sendo usado"</string> <string name="car_mode_disable_notification_message" msgid="7647248420931129377">"Toque para sair do app para carro."</string> - <string name="tethered_notification_title" msgid="3146694234398202601">"Vínculo ou ponto de acesso ativo"</string> + <string name="tethered_notification_title" msgid="3146694234398202601">"Ponto de acesso ou tethering ativo"</string> <string name="tethered_notification_message" msgid="2113628520792055377">"Toque para configurar."</string> <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering desativado"</string> <string name="disable_tether_notification_message" msgid="2913366428516852495">"Fale com seu administrador para saber detalhes"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index a8be5952718d..8a83b774826e 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1476,7 +1476,7 @@ <string name="submit" msgid="1602335572089911941">"Enviar"</string> <string name="car_mode_disable_notification_title" msgid="5704265646471239078">"O app para carro está sendo usado"</string> <string name="car_mode_disable_notification_message" msgid="7647248420931129377">"Toque para sair do app para carro."</string> - <string name="tethered_notification_title" msgid="3146694234398202601">"Vínculo ou ponto de acesso ativo"</string> + <string name="tethered_notification_title" msgid="3146694234398202601">"Ponto de acesso ou tethering ativo"</string> <string name="tethered_notification_message" msgid="2113628520792055377">"Toque para configurar."</string> <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering desativado"</string> <string name="disable_tether_notification_message" msgid="2913366428516852495">"Fale com seu administrador para saber detalhes"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 91f16e8cc234..c438b1bd061f 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1300,7 +1300,7 @@ <string name="wifi_available_action_connect" msgid="2635699628459488788">"Vzpostavi povezavo"</string> <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Vsa omrežja"</string> <string name="wifi_suggestion_title" msgid="6396033039578436801">"Želite dovoliti predlagana omrežja Wi-Fi?"</string> - <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> – predlagana omrežja Naprava se lahko poveže samodejno."</string> + <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> – predlagana omrežja. Naprava se lahko poveže samodejno."</string> <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Dovoli"</string> <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ne, hvala"</string> <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Povezava Wi‑Fi se bo samodejno vklopila"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index d45adafedb77..fa3b001f0233 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -291,7 +291,7 @@ <string name="permgrouprequest_calendar" msgid="289900767793189421">"మీ క్యాలెండర్ని యాక్సెస్ చేయడానికి <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ని అనుమతించాలా?"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS సందేశాలను పంపడం మరియు వీక్షించడం"</string> - <string name="permgrouprequest_sms" msgid="7168124215838204719">"SMS సందేశాలు పంపడానికి మరియు వీక్షించడానికి <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ని అనుమతించాలా?"</string> + <string name="permgrouprequest_sms" msgid="7168124215838204719">"SMS సందేశాలు పంపడం, చూడటం చేయగలిగేలా <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ను అనుమతించాలా?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"నిల్వ"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైల్లను యాక్సెస్ చేయడానికి"</string> <string name="permgrouprequest_storage" msgid="7885942926944299560">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైల్లను యాక్సెస్ చేయడానికి <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ను అనుమతించాలా?"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 90ebf08bdc9a..8f756b650e38 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -282,7 +282,7 @@ <string name="permgrouprequest_contacts" msgid="6032805601881764300">"允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>访问您的通讯录吗?"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string> <string name="permgroupdesc_location" msgid="1346617465127855033">"获取此设备的位置信息"</string> - <string name="permgrouprequest_location" msgid="3788275734953323491">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”获取此设备的位置信息吗?"</string> + <string name="permgrouprequest_location" msgid="3788275734953323491">"要允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”获取此设备的位置信息吗?"</string> <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"只有当您使用该应用时,该应用才有权访问位置信息"</string> <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"要<b>一律允许</b>允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>访问此设备的位置信息吗?"</string> <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"目前只有当您使用该应用时,该应用才能访问位置信息"</string> @@ -291,7 +291,7 @@ <string name="permgrouprequest_calendar" msgid="289900767793189421">"允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>访问您的日历吗?"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"短信"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"发送和查看短信"</string> - <string name="permgrouprequest_sms" msgid="7168124215838204719">"允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>发送和查看短信吗?"</string> + <string name="permgrouprequest_sms" msgid="7168124215838204719">"要允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>发送和查看短信吗?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"存储空间"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"访问您设备上的照片、媒体内容和文件"</string> <string name="permgrouprequest_storage" msgid="7885942926944299560">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”<b></b>访问您设备上的照片、媒体内容和文件吗?"</string> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index b35a9e9c8af9..71bd80229830 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -5009,9 +5009,9 @@ <string name="importance_from_person">This is important because of the people involved.</string> <!-- Message to user that app trying to create user for an account that already exists. [CHAR LIMIT=none] --> - <string name="user_creation_account_exists">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar@gmail.com">%2$s</xliff:g> ?</string> + <string name="user_creation_account_exists">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar@gmail.com">%2$s</xliff:g> (a User with this account already exists) ?</string> <!-- Message to user that app is trying to create user for a specified account. [CHAR LIMIT=none] --> - <string name="user_creation_adding">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar">%2$s</xliff:g> (a User with this account already exists) ?</string> + <string name="user_creation_adding">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar@gmail.com">%2$s</xliff:g> ?</string> <!-- Locale picker strings --> diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 233f82640a20..65f784dbee83 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -205,6 +205,10 @@ targetSdk="29"> <new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" /> </split-permission> + <split-permission name="android.permission.READ_EXTERNAL_STORAGE" + targetSdk="29"> + <new-permission name="android.permission.ACCESS_MEDIA_LOCATION" /> + </split-permission> <!-- This is a list of all the libraries available for application code to link against. --> diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index e6eaa6964d49..b9945cc735d8 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -207,7 +207,7 @@ public class GradientDrawable extends Drawable { } public GradientDrawable() { - this(new GradientState(Orientation.LEFT_RIGHT, null), null); + this(new GradientState(Orientation.TOP_BOTTOM, null), null); } /** diff --git a/packages/CarSystemUI/res/layout/super_status_bar.xml b/packages/CarSystemUI/res/layout/super_status_bar.xml index 728a239a4ca9..e1bcc2e5f86c 100644 --- a/packages/CarSystemUI/res/layout/super_status_bar.xml +++ b/packages/CarSystemUI/res/layout/super_status_bar.xml @@ -42,6 +42,14 @@ </com.android.systemui.statusbar.BackDropView> <com.android.systemui.statusbar.ScrimView + android:id="@+id/scrim_for_bubble" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:importantForAccessibility="no" + sysui:ignoreRightInset="true" + /> + + <com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_behind" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java index 6209c2c36206..a94952c5bc19 100644 --- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java +++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java @@ -19,7 +19,6 @@ package com.android.systemui; import android.animation.ArgbEvaluator; import android.content.Context; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; @@ -28,7 +27,6 @@ import android.util.DisplayMetrics; import android.view.ContextThemeWrapper; import android.view.View; -import com.android.internal.graphics.ColorUtils; import com.android.settingslib.Utils; /** @@ -109,7 +107,6 @@ public class CornerHandleView extends View { mPaint.setColor((int) ArgbEvaluator.getInstance().evaluate(darkIntensity, mLightColor, mDarkColor)); - updateShadow(); if (getVisibility() == VISIBLE) { invalidate(); } @@ -121,21 +118,6 @@ public class CornerHandleView extends View { canvas.drawPath(mPath, mPaint); } - private void updateShadow() { - if (ColorUtils.calculateLuminance(mPaint.getColor()) > 0.7f) { - mPaint.setShadowLayer(/** radius */ 5,/** shadowDx */ 0, /** shadowDy */ -1, - /** color */ ColorUtils.setAlphaComponent(/** color */ Color.BLACK, - /** alpha */ 102)); - } else { - mPaint.setShadowLayer(/** radius */ 0, /** shadowDx */ 0, /** shadowDy */ 0, - /** color */ Color.TRANSPARENT); - } - - if (getVisibility() == VISIBLE) { - invalidate(); - } - } - private static float convertDpToPixel(float dp, Context context) { return dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT); diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java index 46e08661cd70..96b62ac918ab 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java @@ -16,20 +16,14 @@ package com.android.systemui; -import android.annotation.NonNull; import android.app.Notification; import android.app.NotificationManager; import android.content.Context; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.service.notification.StatusBarNotification; -import android.util.ArraySet; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.NotificationVisibility; -import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -72,9 +66,6 @@ public class ForegroundServiceNotificationListener { removeNotification(entry.notification); } }); - - notificationEntryManager.addNotificationLifetimeExtender( - new ForegroundServiceNotificationListener.ForegroundServiceLifetimeExtender()); } /** @@ -153,65 +144,4 @@ public class ForegroundServiceNotificationListener { }, true /* create if not found */); } - - /** - * Extends the lifetime of foreground notification services such that they show for at least - * five seconds - */ - public static class ForegroundServiceLifetimeExtender implements NotificationLifetimeExtender { - - private static final String TAG = "FGSLifetimeExtender"; - @VisibleForTesting - static final int MIN_FGS_TIME_MS = 5000; - - private NotificationSafeToRemoveCallback mNotificationSafeToRemoveCallback; - private ArraySet<NotificationEntry> mManagedEntries = new ArraySet<>(); - private Handler mHandler = new Handler(Looper.getMainLooper()); - - public ForegroundServiceLifetimeExtender() { - } - - @Override - public void setCallback(@NonNull NotificationSafeToRemoveCallback callback) { - mNotificationSafeToRemoveCallback = callback; - } - - @Override - public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) { - if ((entry.notification.getNotification().flags - & Notification.FLAG_FOREGROUND_SERVICE) == 0) { - return false; - } - - long currentTime = System.currentTimeMillis(); - return currentTime - entry.notification.getPostTime() < MIN_FGS_TIME_MS; - } - - @Override - public boolean shouldExtendLifetimeForPendingNotification( - @NonNull NotificationEntry entry) { - return shouldExtendLifetime(entry); - } - - @Override - public void setShouldManageLifetime( - @NonNull NotificationEntry entry, boolean shouldManage) { - if (!shouldManage) { - mManagedEntries.remove(entry); - return; - } - - mManagedEntries.add(entry); - - Runnable r = () -> { - if (mManagedEntries.contains(entry)) { - if (mNotificationSafeToRemoveCallback != null) { - mNotificationSafeToRemoveCallback.onSafeToRemove(entry.key); - } - mManagedEntries.remove(entry); - } - }; - mHandler.postDelayed(r, MIN_FGS_TIME_MS); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleLikeHomeBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleLikeHomeBehavior.java index fa6ffe143022..31115bb940ad 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleLikeHomeBehavior.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleLikeHomeBehavior.java @@ -22,6 +22,7 @@ import androidx.annotation.Nullable; import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.shared.system.QuickStepContract; @@ -39,26 +40,33 @@ import dagger.Lazy; @Singleton final class AssistHandleLikeHomeBehavior implements BehaviorController { + private final StatusBarStateController.StateListener mStatusBarStateListener = + new StatusBarStateController.StateListener() { + @Override + public void onDozingChanged(boolean isDozing) { + handleDozingChanged(isDozing); + } + }; private final WakefulnessLifecycle.Observer mWakefulnessLifecycleObserver = new WakefulnessLifecycle.Observer() { @Override public void onStartedWakingUp() { - handleDozingChanged(/* isDozing = */ true); + handleWakefullnessChanged(/* isAwake = */ false); } @Override public void onFinishedWakingUp() { - handleDozingChanged(/* isDozing = */ false); + handleWakefullnessChanged(/* isAwake = */ true); } @Override public void onStartedGoingToSleep() { - handleDozingChanged(/* isDozing = */ true); + handleWakefullnessChanged(/* isAwake = */ false); } @Override public void onFinishedGoingToSleep() { - handleDozingChanged(/* isDozing = */ true); + handleWakefullnessChanged(/* isAwake = */ false); } }; private final OverviewProxyService.OverviewProxyListener mOverviewProxyListener = @@ -69,19 +77,22 @@ final class AssistHandleLikeHomeBehavior implements BehaviorController { } }; - + private final Lazy<StatusBarStateController> mStatusBarStateController; private final Lazy<WakefulnessLifecycle> mWakefulnessLifecycle; private final Lazy<OverviewProxyService> mOverviewProxyService; private boolean mIsDozing; + private boolean mIsAwake; private boolean mIsHomeHandleHiding; @Nullable private AssistHandleCallbacks mAssistHandleCallbacks; @Inject AssistHandleLikeHomeBehavior( + Lazy<StatusBarStateController> statusBarStateController, Lazy<WakefulnessLifecycle> wakefulnessLifecycle, Lazy<OverviewProxyService> overviewProxyService) { + mStatusBarStateController = statusBarStateController; mWakefulnessLifecycle = wakefulnessLifecycle; mOverviewProxyService = overviewProxyService; } @@ -89,8 +100,10 @@ final class AssistHandleLikeHomeBehavior implements BehaviorController { @Override public void onModeActivated(Context context, AssistHandleCallbacks callbacks) { mAssistHandleCallbacks = callbacks; - mIsDozing = mWakefulnessLifecycle.get().getWakefulness() - != WakefulnessLifecycle.WAKEFULNESS_AWAKE; + mIsDozing = mStatusBarStateController.get().isDozing(); + mStatusBarStateController.get().addCallback(mStatusBarStateListener); + mIsAwake = mWakefulnessLifecycle.get().getWakefulness() + == WakefulnessLifecycle.WAKEFULNESS_AWAKE; mWakefulnessLifecycle.get().addObserver(mWakefulnessLifecycleObserver); mOverviewProxyService.get().addCallback(mOverviewProxyListener); callbackForCurrentState(); @@ -99,6 +112,7 @@ final class AssistHandleLikeHomeBehavior implements BehaviorController { @Override public void onModeDeactivated() { mAssistHandleCallbacks = null; + mStatusBarStateController.get().removeCallback(mStatusBarStateListener); mWakefulnessLifecycle.get().removeObserver(mWakefulnessLifecycleObserver); mOverviewProxyService.get().removeCallback(mOverviewProxyListener); } @@ -116,6 +130,15 @@ final class AssistHandleLikeHomeBehavior implements BehaviorController { callbackForCurrentState(); } + private void handleWakefullnessChanged(boolean isAwake) { + if (mIsAwake == isAwake) { + return; + } + + mIsAwake = isAwake; + callbackForCurrentState(); + } + private void handleSystemUiStateChange(int sysuiStateFlags) { boolean isHomeHandleHiding = isHomeHandleHiding(sysuiStateFlags); if (mIsHomeHandleHiding == isHomeHandleHiding) { @@ -131,18 +154,23 @@ final class AssistHandleLikeHomeBehavior implements BehaviorController { return; } - if (mIsHomeHandleHiding || mIsDozing) { + if (mIsHomeHandleHiding || !isFullyAwake()) { mAssistHandleCallbacks.hide(); } else { mAssistHandleCallbacks.showAndStay(); } } + private boolean isFullyAwake() { + return mIsAwake && !mIsDozing; + } + @Override public void dump(PrintWriter pw, String prefix) { - pw.println("Current AssistHandleLikeHomeBehavior State:"); + pw.println(prefix + "Current AssistHandleLikeHomeBehavior State:"); pw.println(prefix + " mIsDozing=" + mIsDozing); + pw.println(prefix + " mIsAwake=" + mIsAwake); pw.println(prefix + " mIsHomeHandleHiding=" + mIsHomeHandleHiding); } } diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java index a567315f0296..039404800fbb 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java @@ -93,6 +93,11 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { public void onStateChanged(int newState) { handleStatusBarStateChanged(newState); } + + @Override + public void onDozingChanged(boolean isDozing) { + handleDozingChanged(isDozing); + } }; private final TaskStackChangeListener mTaskStackChangeListener = new TaskStackChangeListener() { @@ -121,15 +126,25 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { private final WakefulnessLifecycle.Observer mWakefulnessLifecycleObserver = new WakefulnessLifecycle.Observer() { @Override + public void onStartedWakingUp() { + handleWakefullnessChanged(/* isAwake = */ false); + } + + @Override public void onFinishedWakingUp() { - handleDozingChanged(false); + handleWakefullnessChanged(/* isAwake = */ true); } @Override public void onStartedGoingToSleep() { - handleDozingChanged(true); + handleWakefullnessChanged(/* isAwake = */ false); } - }; + + @Override + public void onFinishedGoingToSleep() { + handleWakefullnessChanged(/* isAwake = */ false); + } + }; private final BroadcastReceiver mDefaultHomeBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -150,6 +165,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { private boolean mOnLockscreen; private boolean mIsDozing; + private boolean mIsAwake; private int mRunningTaskId; private boolean mIsNavBarHidden; private boolean mIsLauncherShowing; @@ -200,14 +216,15 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { mDefaultHome = getCurrentDefaultHome(); context.registerReceiver(mDefaultHomeBroadcastReceiver, mDefaultHomeIntentFilter); mOnLockscreen = onLockscreen(mStatusBarStateController.get().getState()); + mIsDozing = mStatusBarStateController.get().isDozing(); mStatusBarStateController.get().addCallback(mStatusBarStateListener); ActivityManager.RunningTaskInfo runningTaskInfo = mActivityManagerWrapper.get().getRunningTask(); mRunningTaskId = runningTaskInfo == null ? 0 : runningTaskInfo.taskId; mActivityManagerWrapper.get().registerTaskStackListener(mTaskStackChangeListener); mOverviewProxyService.get().addCallback(mOverviewProxyListener); - mIsDozing = mWakefulnessLifecycle.get().getWakefulness() - != WakefulnessLifecycle.WAKEFULNESS_AWAKE; + mIsAwake = mWakefulnessLifecycle.get().getWakefulness() + == WakefulnessLifecycle.WAKEFULNESS_AWAKE; mWakefulnessLifecycle.get().addObserver(mWakefulnessLifecycleObserver); mLearningTimeElapsed = Settings.Secure.getLong( @@ -249,7 +266,10 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { @Override public void onAssistHandlesRequested() { - if (mAssistHandleCallbacks != null && !mIsDozing && !mIsNavBarHidden && !mOnLockscreen) { + if (mAssistHandleCallbacks != null + && isFullyAwake() + && !mIsNavBarHidden + && !mOnLockscreen) { mAssistHandleCallbacks.showAndGo(); } } @@ -296,6 +316,16 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { callbackForCurrentState(/* justUnlocked = */ false); } + private void handleWakefullnessChanged(boolean isAwake) { + if (mIsAwake == isAwake) { + return; + } + + resetConsecutiveTaskSwitches(); + mIsAwake = isAwake; + callbackForCurrentState(/* justUnlocked = */ false); + } + private void handleTaskStackTopChanged(int taskId, @Nullable ComponentName taskComponentName) { if (mRunningTaskId == taskId || taskComponentName == null) { return; @@ -349,7 +379,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { return; } - if (mIsDozing || mIsNavBarHidden || mOnLockscreen || !getShowWhenTaught()) { + if (!isFullyAwake() || mIsNavBarHidden || mOnLockscreen || !getShowWhenTaught()) { mAssistHandleCallbacks.hide(); } else if (justUnlocked) { long currentEpochDay = LocalDate.now().toEpochDay(); @@ -371,7 +401,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { return; } - if (mIsDozing || mIsNavBarHidden || isSuppressed()) { + if (!isFullyAwake() || mIsNavBarHidden || isSuppressed()) { mAssistHandleCallbacks.hide(); } else if (mOnLockscreen) { mAssistHandleCallbacks.showAndStay(); @@ -422,6 +452,10 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { mHandler.postDelayed(mResetConsecutiveTaskSwitches, getShowAndGoDelayResetTimeoutMs()); } + private boolean isFullyAwake() { + return mIsAwake && !mIsDozing; + } + private long getLearningTimeMs() { return mPhenotypeHelper.getLong( SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_TIME_MS, @@ -481,6 +515,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { pw.println(prefix + "Current AssistHandleReminderExpBehavior State:"); pw.println(prefix + " mOnLockscreen=" + mOnLockscreen); pw.println(prefix + " mIsDozing=" + mIsDozing); + pw.println(prefix + " mIsAwake=" + mIsAwake); pw.println(prefix + " mRunningTaskId=" + mRunningTaskId); pw.println(prefix + " mDefaultHome=" + mDefaultHome); pw.println(prefix + " mIsNavBarHidden=" + mIsNavBarHidden); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 94d9ede5c8b1..3cc91de43438 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -560,7 +560,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // Need to check for !appCancel here because the notification may have // previously been dismissed & entry.isRowDismissed would still be true - boolean userRemovedNotif = (entry.isRowDismissed() && !isAppCancel) + boolean userRemovedNotif = (entry != null && entry.isRowDismissed() && !isAppCancel) || isClearAll || isUserDimiss || isSummaryCancel; if (isSummaryOfBubbles) { @@ -570,7 +570,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // The bubble notification sticks around in the data as long as the bubble is // not dismissed and the app hasn't cancelled the notification. Bubble bubble = mBubbleData.getBubbleWithKey(key); - boolean bubbleExtended = entry.isBubble() && userRemovedNotif; + boolean bubbleExtended = entry != null && entry.isBubble() && userRemovedNotif; if (bubbleExtended) { bubble.setShowInShadeWhenBubble(false); bubble.setShowBubbleDot(false); @@ -579,7 +579,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } mNotificationEntryManager.updateNotifications(); return true; - } else if (!userRemovedNotif) { + } else if (!userRemovedNotif && entry != null) { // This wasn't a user removal so we should remove the bubble as well mBubbleData.notificationEntryRemoved(entry, DISMISS_NOTIF_CANCEL); return false; @@ -926,7 +926,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @Override public void onSingleTaskDisplayDrawn(int displayId) { - final Bubble expandedBubble = getExpandedBubble(mContext); + final Bubble expandedBubble = mStackView != null + ? mStackView.getExpandedBubble() + : null; if (expandedBubble != null && expandedBubble.getDisplayId() == displayId) { expandedBubble.setContentVisibility(true); } @@ -934,14 +936,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @Override public void onSingleTaskDisplayEmpty(int displayId) { - final Bubble expandedBubble = getExpandedBubble(mContext); - if (expandedBubble == null) { - return; - } - if (expandedBubble.getDisplayId() == displayId) { + final Bubble expandedBubble = mStackView != null + ? mStackView.getExpandedBubble() + : null; + int expandedId = expandedBubble != null ? expandedBubble.getDisplayId() : -1; + if (mStackView != null && mStackView.isExpanded() && expandedId == displayId) { mBubbleData.setExpanded(false); - expandedBubble.getExpandedView().notifyDisplayEmpty(); } + mBubbleData.notifyDisplayEmpty(displayId); } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java index 81c8da8247ec..eb826e54d340 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java @@ -392,6 +392,22 @@ public class BubbleData { dispatchPendingChanges(); } + /** + * Indicates that the provided display is no longer in use and should be cleaned up. + * + * @param displayId the id of the display to clean up. + */ + void notifyDisplayEmpty(int displayId) { + for (Bubble b : mBubbles) { + if (b.getDisplayId() == displayId) { + if (b.getExpandedView() != null) { + b.getExpandedView().notifyDisplayEmpty(); + } + return; + } + } + } + private void dispatchPendingChanges() { if (mListener != null && mStateChange.anythingChanged()) { mListener.applyUpdate(mStateChange); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index be10dc565159..521ebde7d2f0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -105,6 +105,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList private Drawable mAppIcon; private BubbleController mBubbleController = Dependency.get(BubbleController.class); + private WindowManager mWindowManager; private BubbleStackView mStackView; @@ -202,9 +203,9 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList super(context, attrs, defStyleAttr, defStyleRes); mPm = context.getPackageManager(); mDisplaySize = new Point(); - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); // Get the real size -- this includes screen decorations (notches, statusbar, navbar). - wm.getDefaultDisplay().getRealSize(mDisplaySize); + mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize); Resources res = getResources(); mMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height); mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin); @@ -326,7 +327,10 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList if (usingActivityView()) { int[] screenLoc = mActivityView.getLocationOnScreen(); final int activityViewBottom = screenLoc[1] + mActivityView.getHeight(); - final int keyboardTop = mDisplaySize.y - insets.getSystemWindowInsetBottom(); + final int keyboardTop = mDisplaySize.y - Math.max(insets.getSystemWindowInsetBottom(), + insets.getDisplayCutout() != null + ? insets.getDisplayCutout().getSafeInsetBottom() + : 0); final int insetsBottom = Math.max(activityViewBottom - keyboardTop, 0); mActivityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom)); } @@ -444,6 +448,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList } private int getMaxExpandedHeight() { + mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize); int[] windowLocation = mActivityView.getLocationOnScreen(); int bottomInset = getRootWindowInsets() != null ? getRootWindowInsets().getStableInsetBottom() diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 13d6470a351f..b68b7627fe8c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -45,6 +45,7 @@ import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.StatsLog; import android.view.Choreographer; +import android.view.DisplayCutout; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -340,7 +341,8 @@ public class BubbleStackView extends FrameLayout { mDisplaySize = new Point(); WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - wm.getDefaultDisplay().getSize(mDisplaySize); + // We use the real size & subtract screen decorations / window insets ourselves when needed + wm.getDefaultDisplay().getRealSize(mDisplaySize); mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); @@ -417,7 +419,35 @@ public class BubbleStackView extends FrameLayout { mOrientationChangedListener = (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { - mExpandedAnimationController.updateOrientation(mOrientation); + mExpandedAnimationController.updateOrientation(mOrientation, mDisplaySize); + mStackAnimationController.updateOrientation(mOrientation); + + // Reposition & adjust the height for new orientation + if (mIsExpanded) { + mExpandedViewContainer.setTranslationY(getExpandedViewY()); + mExpandedBubble.getExpandedView().updateView(); + } + + // Need to update the padding around the view + WindowInsets insets = getRootWindowInsets(); + int leftPadding = mExpandedViewPadding; + int rightPadding = mExpandedViewPadding; + if (insets != null) { + // Can't have the expanded view overlaying notches + int cutoutLeft = 0; + int cutoutRight = 0; + DisplayCutout cutout = insets.getDisplayCutout(); + if (cutout != null) { + cutoutLeft = cutout.getSafeInsetLeft(); + cutoutRight = cutout.getSafeInsetRight(); + } + // Or overlaying nav or status bar + leftPadding += Math.max(cutoutLeft, insets.getStableInsetLeft()); + rightPadding += Math.max(cutoutRight, insets.getStableInsetRight()); + } + mExpandedViewContainer.setPadding(leftPadding, mExpandedViewPadding, + rightPadding, mExpandedViewPadding); + if (mIsExpanded) { // Re-draw bubble row and pointer for new orientation. mExpandedAnimationController.expandFromStack(() -> { @@ -488,6 +518,11 @@ public class BubbleStackView extends FrameLayout { public void onOrientationChanged(int orientation) { mOrientation = orientation; + // Display size is based on the rotation device was in when requested, we should update it + // We use the real size & subtract screen decorations / window insets ourselves when needed + WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getRealSize(mDisplaySize); + // Some resources change depending on orientation Resources res = getContext().getResources(); mStatusBarHeight = res.getDimensionPixelSize( @@ -1589,11 +1624,9 @@ public class BubbleStackView extends FrameLayout { int index = getBubbleIndex(expandedBubble); float bubbleLeftFromScreenLeft = mExpandedAnimationController.getBubbleLeft(index); float halfBubble = mBubbleSize / 2f; - - // Bubbles live in expanded view container (x includes expanded view padding). - // Pointer lives in expanded view, which has padding (x does not include padding). - // Remove padding when deriving pointer location from bubbles. - float bubbleCenter = bubbleLeftFromScreenLeft + halfBubble - mExpandedViewPadding; + float bubbleCenter = bubbleLeftFromScreenLeft + halfBubble; + // Padding might be adjusted for insets, so get it directly from the view + bubbleCenter -= mExpandedViewContainer.getPaddingLeft(); expandedBubble.getExpandedView().setPointerPosition(bubbleCenter); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java index c332d15a9b47..59d68bca93c3 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java @@ -21,6 +21,7 @@ import android.content.res.Resources; import android.graphics.Path; import android.graphics.Point; import android.graphics.PointF; +import android.view.DisplayCutout; import android.view.View; import android.view.WindowInsets; @@ -57,6 +58,9 @@ public class ExpandedAnimationController /** Stiffness for the expand/collapse path-following animation. */ private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 1000; + /** What percentage of the screen to use when centering the bubbles in landscape. */ + private static final float CENTER_BUBBLES_LANDSCAPE_PERCENT = 0.66f; + /** Horizontal offset between bubbles, which we need to know to re-stack them. */ private float mStackOffsetPx; /** Space between status bar and bubbles in the expanded state. */ @@ -69,8 +73,8 @@ public class ExpandedAnimationController private Point mDisplaySize; /** Max number of bubbles shown in row above expanded view.*/ private int mBubblesMaxRendered; - /** Width of current screen orientation. */ - private float mScreenWidth; + /** What the current screen orientation is. */ + private int mScreenOrientation; /** Whether the dragged-out bubble is in the dismiss target. */ private boolean mIndividualBubbleWithinDismissTarget = false; @@ -97,8 +101,7 @@ public class ExpandedAnimationController public ExpandedAnimationController(Point displaySize, int expandedViewPadding, int orientation) { - mDisplaySize = displaySize; - updateOrientation(orientation); + updateOrientation(orientation, displaySize); mExpandedViewPadding = expandedViewPadding; mLauncherGridDiff = 30f; } @@ -136,18 +139,16 @@ public class ExpandedAnimationController /** * Update effective screen width based on current orientation. * @param orientation Landscape or portrait. + * @param displaySize Updated display size. */ - public void updateOrientation(int orientation) { - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - mScreenWidth = mDisplaySize.y; - } else { - mScreenWidth = mDisplaySize.x; - } + public void updateOrientation(int orientation, Point displaySize) { + mScreenOrientation = orientation; + mDisplaySize = displaySize; if (mLayout != null) { Resources res = mLayout.getContext().getResources(); + mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); mStatusBarHeight = res.getDimensionPixelSize( com.android.internal.R.dimen.status_bar_height); - mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); } } @@ -499,6 +500,50 @@ public class ExpandedAnimationController return getRowLeft() + bubbleFromRowLeft; } + /** + * When expanded, the bubbles are centered in the screen. In portrait, all available space is + * used. In landscape we have too much space so the value is restricted. This method accounts + * for window decorations (nav bar, cutouts). + * + * @return the desired width to display the expanded bubbles in. + */ + private float getWidthForDisplayingBubbles() { + final float availableWidth = getAvailableScreenWidth(true /* includeStableInsets */); + if (mScreenOrientation == Configuration.ORIENTATION_LANDSCAPE) { + // display size y in landscape will be the smaller dimension of the screen + return Math.max(mDisplaySize.y, availableWidth * CENTER_BUBBLES_LANDSCAPE_PERCENT); + } else { + return availableWidth; + } + } + + /** + * Determines the available screen width without the cutout. + * + * @param subtractStableInsets Whether or not stable insets should also be removed from the + * returned width. + * @return the total screen width available accounting for cutouts and insets, + * iff {@param includeStableInsets} is true. + */ + private float getAvailableScreenWidth(boolean subtractStableInsets) { + float availableSize = mDisplaySize.x; + WindowInsets insets = mLayout != null ? mLayout.getRootWindowInsets() : null; + if (insets != null) { + int cutoutLeft = 0; + int cutoutRight = 0; + DisplayCutout cutout = insets.getDisplayCutout(); + if (cutout != null) { + cutoutLeft = cutout.getSafeInsetLeft(); + cutoutRight = cutout.getSafeInsetRight(); + } + final int stableLeft = subtractStableInsets ? insets.getStableInsetLeft() : 0; + final int stableRight = subtractStableInsets ? insets.getStableInsetRight() : 0; + availableSize -= Math.max(stableLeft, cutoutLeft); + availableSize -= Math.max(stableRight, cutoutRight); + } + return availableSize; + } + private float getRowLeft() { if (mLayout == null) { return 0; @@ -510,9 +555,12 @@ public class ExpandedAnimationController final float totalGapWidth = (bubbleCount - 1) * getSpaceBetweenBubbles(); final float rowWidth = totalGapWidth + totalBubbleWidth; - final float centerScreen = mScreenWidth / 2f; + // This display size we're using includes the size of the insets, we want the true + // center of the display minus the notch here, which means we should include the + // stable insets (e.g. status bar, nav bar) in this calculation. + final float trueCenter = getAvailableScreenWidth(false /* subtractStableInsets */) / 2f; final float halfRow = rowWidth / 2f; - final float rowLeft = centerScreen - halfRow; + final float rowLeft = trueCenter - halfRow; return rowLeft; } @@ -530,7 +578,7 @@ public class ExpandedAnimationController * Launcher's app icon grid edge that we must match */ final float rowMargins = (mExpandedViewPadding + mLauncherGridDiff) * 2; - final float maxRowWidth = mScreenWidth - rowMargins; + final float maxRowWidth = getWidthForDisplayingBubbles() - rowMargins; final float totalBubbleWidth = mBubblesMaxRendered * mBubbleSizePx; final float totalGapWidth = maxRowWidth - totalBubbleWidth; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index ee79e6b973de..cff06227b857 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -27,14 +27,13 @@ import android.view.MotionEvent; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.Dependency; import com.android.systemui.classifier.brightline.BrightLineFalsingManager; import com.android.systemui.classifier.brightline.FalsingDataProvider; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.FalsingPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.util.AsyncSensorManager; +import com.android.systemui.util.ProximitySensor; import java.io.PrintWriter; @@ -50,18 +49,23 @@ import javax.inject.Singleton; @Singleton public class FalsingManagerProxy implements FalsingManager { + private static final String PROXIMITY_SENSOR_TAG = "FalsingManager"; + + private final ProximitySensor mProximitySensor; private FalsingManager mInternalFalsingManager; private final Handler mMainHandler; @Inject FalsingManagerProxy(Context context, PluginManager pluginManager, - @Named(MAIN_HANDLER_NAME) Handler handler) { + @Named(MAIN_HANDLER_NAME) Handler handler, + ProximitySensor proximitySensor) { mMainHandler = handler; + mProximitySensor = proximitySensor; + mProximitySensor.setTag(PROXIMITY_SENSOR_TAG); DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, command -> mMainHandler.post(command), properties -> onDeviceConfigPropertiesChanged(context, properties.getNamespace()) - ); - setupFalsingManager(context); + ); setupFalsingManager(context); final PluginListener<FalsingPlugin> mPluginListener = new PluginListener<FalsingPlugin>() { public void onPluginConnected(FalsingPlugin plugin, Context context) { FalsingManager pluginFalsingManager = plugin.getFalsingManager(context); @@ -103,8 +107,8 @@ public class FalsingManagerProxy implements FalsingManager { } else { mInternalFalsingManager = new BrightLineFalsingManager( new FalsingDataProvider(context.getResources().getDisplayMetrics()), - Dependency.get(AsyncSensorManager.class), - KeyguardUpdateMonitor.getInstance(context) + KeyguardUpdateMonitor.getInstance(context), + mProximitySensor ); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java index 9e0b7025ddf8..b68a56dcc750 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java @@ -19,10 +19,6 @@ package com.android.systemui.classifier.brightline; import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_REMAIN_LOCKED; import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_SUCCESS; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; import android.hardware.biometrics.BiometricSourceType; import android.net.Uri; import android.util.Log; @@ -33,12 +29,11 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.classifier.Classifier; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.util.ProximitySensor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; /** * FalsingManager designed to make clear why a touch was rejected. @@ -48,9 +43,9 @@ public class BrightLineFalsingManager implements FalsingManager { static final boolean DEBUG = false; private static final String TAG = "FalsingManagerPlugin"; - private final SensorManager mSensorManager; private final FalsingDataProvider mDataProvider; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final ProximitySensor mProximitySensor; private boolean mSessionStarted; private MetricsLogger mMetricsLogger; private int mIsFalseTouchCalls; @@ -58,20 +53,9 @@ public class BrightLineFalsingManager implements FalsingManager { private boolean mScreenOn; private boolean mJustUnlockedWithFace; - private final ExecutorService mBackgroundExecutor = Executors.newSingleThreadExecutor(); - private final List<FalsingClassifier> mClassifiers; - private SensorEventListener mSensorEventListener = new SensorEventListener() { - @Override - public synchronized void onSensorChanged(SensorEvent event) { - onSensorEvent(event); - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } - }; + private ProximitySensor.ProximitySensorListener mSensorEventListener = this::onProximityEvent; private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback = new KeyguardUpdateMonitorCallback() { @@ -87,11 +71,11 @@ public class BrightLineFalsingManager implements FalsingManager { public BrightLineFalsingManager( FalsingDataProvider falsingDataProvider, - SensorManager sensorManager, - KeyguardUpdateMonitor keyguardUpdateMonitor) { + KeyguardUpdateMonitor keyguardUpdateMonitor, + ProximitySensor proximitySensor) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mDataProvider = falsingDataProvider; - mSensorManager = sensorManager; + mProximitySensor = proximitySensor; mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); mMetricsLogger = new MetricsLogger(); @@ -108,24 +92,12 @@ public class BrightLineFalsingManager implements FalsingManager { } private void registerSensors() { - Sensor s = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); - if (s != null) { - // This can be expensive, and doesn't need to happen on the main thread. - mBackgroundExecutor.submit(() -> { - logDebug("registering sensor listener"); - mSensorManager.registerListener( - mSensorEventListener, s, SensorManager.SENSOR_DELAY_GAME); - }); - } + mProximitySensor.register(mSensorEventListener); } private void unregisterSensors() { - // This can be expensive, and doesn't need to happen on the main thread. - mBackgroundExecutor.submit(() -> { - logDebug("unregistering sensor listener"); - mSensorManager.unregisterListener(mSensorEventListener); - }); + mProximitySensor.unregister(mSensorEventListener); } private void sessionStart() { @@ -187,10 +159,10 @@ public class BrightLineFalsingManager implements FalsingManager { mClassifiers.forEach((classifier) -> classifier.onTouchEvent(motionEvent)); } - private void onSensorEvent(SensorEvent sensorEvent) { + private void onProximityEvent(ProximitySensor.ProximityEvent proximityEvent) { // TODO: some of these classifiers might allow us to abort early, meaning we don't have to // make these calls. - mClassifiers.forEach((classifier) -> classifier.onSensorEvent(sensorEvent)); + mClassifiers.forEach((classifier) -> classifier.onProximityEvent(proximityEvent)); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java index 685e7c534b66..bf397518de46 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java @@ -16,10 +16,10 @@ package com.android.systemui.classifier.brightline; -import android.hardware.SensorEvent; import android.view.MotionEvent; import com.android.systemui.classifier.Classifier; +import com.android.systemui.util.ProximitySensor; import java.util.List; @@ -98,9 +98,9 @@ abstract class FalsingClassifier { void onTouchEvent(MotionEvent motionEvent) {}; /** - * Called whenever a SensorEvent occurs, specifically the ProximitySensor. + * Called when a ProximityEvent occurs (change in near/far). */ - void onSensorEvent(SensorEvent sensorEvent) {}; + void onProximityEvent(ProximitySensor.ProximityEvent proximityEvent) {}; /** * The phone screen has turned on and we need to begin falsing detection. diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java index 2644bf9f26ce..5045095a475f 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java @@ -19,11 +19,11 @@ package com.android.systemui.classifier.brightline; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD; import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; -import android.hardware.Sensor; -import android.hardware.SensorEvent; import android.provider.DeviceConfig; import android.view.MotionEvent; +import com.android.systemui.util.ProximitySensor; + /** * False touch if proximity sensor is covered for more than a certain percentage of the gesture. @@ -97,14 +97,12 @@ class ProximityClassifier extends FalsingClassifier { } @Override - public void onSensorEvent(SensorEvent sensorEvent) { - if (sensorEvent.sensor.getType() == Sensor.TYPE_PROXIMITY) { - logDebug("Sensor is: " + (sensorEvent.values[0] < sensorEvent.sensor.getMaximumRange()) - + " at time " + sensorEvent.timestamp); - update( - sensorEvent.values[0] < sensorEvent.sensor.getMaximumRange(), - sensorEvent.timestamp); - } + public void onProximityEvent( + ProximitySensor.ProximityEvent proximityEvent) { + boolean near = proximityEvent.getNear(); + long timestampNs = proximityEvent.getTimestampNs(); + logDebug("Sensor is: " + near + " at time " + timestampNs); + update(near, timestampNs); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java index 48e2923c97d9..0f295ba75fe4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java @@ -27,18 +27,6 @@ public interface NotificationLifetimeExtender { boolean shouldExtendLifetime(@NonNull NotificationEntry entry); /** - * It's possible that a notification was canceled before it ever became visible. This callback - * gives lifetime extenders a chance to make sure it shows up. For example if a foreground - * service is canceled too quickly but we still want to make sure a FGS notification shows. - * @param pendingEntry the canceled (but pending) entry - * @return true if the notification lifetime should be extended - */ - default boolean shouldExtendLifetimeForPendingNotification( - @NonNull NotificationEntry pendingEntry) { - return false; - } - - /** * Sets whether or not the lifetime should be managed by the extender. In practice, if * shouldManage is true, this is where the extender starts managing the entry internally and is * now responsible for calling {@link NotificationSafeToRemoveCallback#onSafeToRemove(String)} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index 276afa7a3a94..a70dc7c0ec5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -33,6 +33,7 @@ import com.android.systemui.Gefingerpoken import com.android.systemui.Interpolators import com.android.systemui.R import com.android.systemui.plugins.FalsingManager +import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView @@ -56,7 +57,8 @@ constructor( private val wakeUpCoordinator: NotificationWakeUpCoordinator, private val bypassController: KeyguardBypassController, private val headsUpManager: HeadsUpManagerPhone, - private val roundnessManager: NotificationRoundnessManager + private val roundnessManager: NotificationRoundnessManager, + private val statusBarStateController: StatusBarStateController ) : Gefingerpoken { companion object { private val RUBBERBAND_FACTOR_STATIC = 0.25f @@ -188,7 +190,8 @@ constructor( MotionEvent.ACTION_MOVE -> updateExpansionHeight(moveDistance) MotionEvent.ACTION_UP -> { velocityTracker!!.computeCurrentVelocity(1000 /* units */) - val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000 + val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000 && + statusBarStateController.state != StatusBarState.SHADE if (!mFalsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) { finishExpansion() } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index f0eeb046bc44..abf29c47e803 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -20,6 +20,7 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.text.format.DateFormat; import android.util.FloatProperty; +import android.util.Log; import android.view.View; import android.view.animation.Interpolator; @@ -136,6 +137,11 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll // Record the to-be mState and mLastState recordHistoricalState(state, mState); + // b/139259891 + if (mState == StatusBarState.SHADE && state == StatusBarState.SHADE_LOCKED) { + Log.e(TAG, "Invalid state transition: SHADE -> SHADE_LOCKED", new Throwable()); + } + synchronized (mListeners) { for (RankedListener rl : new ArrayList<>(mListeners)) { rl.mListener.onStatePreChange(mState, state); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index a37367e4bb25..f8fef7d4778c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -281,24 +281,10 @@ public class NotificationEntryManager implements } final NotificationEntry entry = mNotificationData.get(key); - boolean lifetimeExtended = false; - // Notification was canceled before it got inflated - if (entry == null) { - NotificationEntry pendingEntry = mPendingNotifications.get(key); - if (pendingEntry != null) { - for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) { - if (extender.shouldExtendLifetimeForPendingNotification(pendingEntry)) { - extendLifetime(pendingEntry, extender); - lifetimeExtended = true; - } - } - } - } + abortExistingInflation(key); - if (!lifetimeExtended) { - abortExistingInflation(key); - } + boolean lifetimeExtended = false; if (entry != null) { // If a manager needs to keep the notification around for whatever reason, we diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index 48a82957bf1e..a612a1721c41 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -264,7 +264,7 @@ public class NotificationContentInflater { mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, packageContext); result = inflateSmartReplyViews(result, reInflateFlags, mRow.getEntry(), - mRow.getContext(), mRow.getHeadsUpManager(), + mRow.getContext(), packageContext, mRow.getHeadsUpManager(), mRow.getExistingSmartRepliesAndActions()); apply( inflateSynchronously, @@ -311,20 +311,21 @@ public class NotificationContentInflater { private static InflationProgress inflateSmartReplyViews(InflationProgress result, @InflationFlag int reInflateFlags, NotificationEntry entry, Context context, - HeadsUpManager headsUpManager, SmartRepliesAndActions previousSmartRepliesAndActions) { + Context packageContext, HeadsUpManager headsUpManager, + SmartRepliesAndActions previousSmartRepliesAndActions) { SmartReplyConstants smartReplyConstants = Dependency.get(SmartReplyConstants.class); SmartReplyController smartReplyController = Dependency.get(SmartReplyController.class); if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0 && result.newExpandedView != null) { result.expandedInflatedSmartReplies = InflatedSmartReplies.inflate( - context, entry, smartReplyConstants, smartReplyController, - headsUpManager, previousSmartRepliesAndActions); + context, packageContext, entry, smartReplyConstants, + smartReplyController, headsUpManager, previousSmartRepliesAndActions); } if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0 && result.newHeadsUpView != null) { result.headsUpInflatedSmartReplies = InflatedSmartReplies.inflate( - context, entry, smartReplyConstants, smartReplyController, - headsUpManager, previousSmartRepliesAndActions); + context, packageContext, entry, smartReplyConstants, + smartReplyController, headsUpManager, previousSmartRepliesAndActions); } return result; } @@ -817,7 +818,7 @@ public class NotificationContentInflater { recoveredBuilder, mIsLowPriority, mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, packageContext); return inflateSmartReplyViews(inflationProgress, mReInflateFlags, mRow.getEntry(), - mRow.getContext(), mRow.getHeadsUpManager(), + mRow.getContext(), packageContext, mRow.getHeadsUpManager(), mRow.getExistingSmartRepliesAndActions()); } catch (Exception e) { mError = e; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index ba3406999388..1a3560ece1d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -537,11 +537,7 @@ public class NotificationIconAreaController implements DarkReceiver, if (dozeParameters.shouldControlScreenOff()) { mAodIcons.setTranslationY(-mAodIconAppearTranslation); mAodIcons.setAlpha(0); - mAodIcons.animate() - .setInterpolator(Interpolators.DECELERATE_QUINT) - .translationY(0) - .setDuration(AOD_ICONS_APPEAR_DURATION) - .start(); + animateInAodIconTranslation(); mAodIcons.animate() .alpha(1) .setInterpolator(Interpolators.LINEAR) @@ -550,6 +546,14 @@ public class NotificationIconAreaController implements DarkReceiver, } } + private void animateInAodIconTranslation() { + mAodIcons.animate() + .setInterpolator(Interpolators.DECELERATE_QUINT) + .translationY(0) + .setDuration(AOD_ICONS_APPEAR_DURATION) + .start(); + } + private void reloadAodColor() { mAodIconTint = Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor); @@ -606,14 +610,19 @@ public class NotificationIconAreaController implements DarkReceiver, mAodIcons.setAlpha(1.0f); appearAodIcons(); } else { + // Let's make sure the icon are translated to 0, since we cancelled it above + animateInAodIconTranslation(); // We were fading out, let's fade in instead CrossFadeHelper.fadeIn(mAodIcons); } } else { + // Let's make sure the icon are translated to 0, since we cancelled it above + animateInAodIconTranslation(); CrossFadeHelper.fadeOut(mAodIcons); } } else { mAodIcons.setAlpha(1.0f); + mAodIcons.setTranslationY(0); mAodIcons.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 83c556630538..6bc0cf6e0a3d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -96,6 +96,7 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.ZenModeController; @@ -169,12 +170,22 @@ public class NotificationPanelView extends PanelView implements @VisibleForTesting final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback = new KeyguardUpdateMonitorCallback() { + + @Override + public void onBiometricAuthenticated(int userId, + BiometricSourceType biometricSourceType) { + if (mFirstBypassAttempt && mUpdateMonitor.isUnlockingWithBiometricAllowed()) { + mDelayShowingKeyguardStatusBar = true; + } + } + @Override public void onBiometricRunningStateChanged(boolean running, BiometricSourceType biometricSourceType) { boolean keyguardOrShadeLocked = mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED; - if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing) { + if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing + && !mDelayShowingKeyguardStatusBar) { mFirstBypassAttempt = false; animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD); } @@ -183,6 +194,17 @@ public class NotificationPanelView extends PanelView implements @Override public void onFinishedGoingToSleep(int why) { mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled(); + mDelayShowingKeyguardStatusBar = false; + } + }; + private final KeyguardMonitor.Callback mKeyguardMonitorCallback = + new KeyguardMonitor.Callback() { + @Override + public void onKeyguardFadingAwayChanged() { + if (!mKeyguardMonitor.isKeyguardFadingAway()) { + mFirstBypassAttempt = false; + mDelayShowingKeyguardStatusBar = false; + } } }; @@ -404,7 +426,17 @@ public class NotificationPanelView extends PanelView implements private boolean mShowingKeyguardHeadsUp; private boolean mAllowExpandForSmallExpansion; private Runnable mExpandAfterLayoutRunnable; + + /** + * If face auth with bypass is running for the first time after you turn on the screen. + * (From aod or screen off) + */ private boolean mFirstBypassAttempt; + /** + * If auth happens successfully during {@code mFirstBypassAttempt}, and we should wait until + * the keyguard is dismissed to show the status bar. + */ + private boolean mDelayShowingKeyguardStatusBar; @Inject public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, @@ -436,6 +468,7 @@ public class NotificationPanelView extends PanelView implements mKeyguardBypassController = bypassController; mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled(); + mKeyguardMonitor.addCallback(mKeyguardMonitorCallback); dynamicPrivacyController.addListener(this); mBottomAreaShadeAlphaAnimator = ValueAnimator.ofFloat(1f, 0); @@ -2263,7 +2296,8 @@ public class NotificationPanelView extends PanelView implements * mKeyguardStatusBarAnimateAlpha; newAlpha *= 1.0f - mKeyguardHeadsUpShowingAmount; mKeyguardStatusBar.setAlpha(newAlpha); - boolean hideForBypass = mFirstBypassAttempt && mUpdateMonitor.shouldListenForFace(); + boolean hideForBypass = mFirstBypassAttempt && mUpdateMonitor.shouldListenForFace() + || mDelayShowingKeyguardStatusBar; mKeyguardStatusBar.setVisibility(newAlpha != 0f && !mDozing && !hideForBypass ? VISIBLE : INVISIBLE); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 5733d4b0eb28..45f3b32d8155 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -473,11 +473,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo if (mDarkenWhileDragging) { mBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind, interpolatedFract); - mInFrontAlpha = 0; + mInFrontAlpha = mState.getFrontAlpha(); } else { mBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind, interpolatedFract); - mInFrontAlpha = 0; + mInFrontAlpha = mState.getFrontAlpha(); } mBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(), mState.getBehindTint(), interpolatedFract); @@ -503,13 +503,14 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo * device is dozing when the light sensor is on. */ public void setAodFrontScrimAlpha(float alpha) { - if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn() - && mInFrontAlpha != alpha) { + if (((mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()) + || mState == ScrimState.PULSING) && mInFrontAlpha != alpha) { mInFrontAlpha = alpha; updateScrims(); } mState.AOD.setAodFrontScrimAlpha(alpha); + mState.PULSING.setAodFrontScrimAlpha(alpha); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index c9acbad1e8cf..7463c7c232bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -139,7 +139,7 @@ public enum ScrimState { PULSING(5) { @Override public void prepare(ScrimState previousState) { - mFrontAlpha = 0f; + mFrontAlpha = mAodFrontScrimAlpha; mBubbleAlpha = 0f; mBehindTint = Color.BLACK; mFrontTint = Color.BLACK; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 069219802cc3..a870590c08ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -224,7 +224,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mVisualStabilityManager.setUpWithPresenter(this); mGutsManager.setUpWithPresenter(this, notifListContainer, mCheckSaveListener, mOnSettingsClickListener); - // ForegroundServiceNotificationListener adds its listener in its constructor + // ForegroundServiceControllerListener adds its listener in its constructor // but we need to request it here in order for it to be instantiated. // TODO: figure out how to do this correctly once Dependency.get() is gone. Dependency.get(ForegroundServiceNotificationListener.class); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplies.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplies.java index ee78a723a49c..ea93193ca728 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplies.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplies.java @@ -80,6 +80,7 @@ public class InflatedSmartReplies { */ public static InflatedSmartReplies inflate( Context context, + Context packageContext, NotificationEntry entry, SmartReplyConstants smartReplyConstants, SmartReplyController smartReplyController, @@ -108,9 +109,9 @@ public class InflatedSmartReplies { } if (newSmartRepliesAndActions.smartActions != null) { suggestionButtons.addAll( - smartReplyView.inflateSmartActions(newSmartRepliesAndActions.smartActions, - smartReplyController, entry, headsUpManager, - delayOnClickListener)); + smartReplyView.inflateSmartActions(packageContext, + newSmartRepliesAndActions.smartActions, smartReplyController, entry, + headsUpManager, delayOnClickListener)); } return new InflatedSmartReplies(smartReplyView, suggestionButtons, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index dbfb09f7fc41..5da726749580 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -294,7 +294,8 @@ public class MobileSignalController extends SignalController< } boolean dataDisabled = mCurrentState.userSetup && (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED - || mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA); + || (mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA + && mCurrentState.defaultDataOff)); boolean noInternet = mCurrentState.inetCondition == 0; boolean cutOut = dataDisabled || noInternet; return SignalDrawable.getState(level, getNumLevels(), cutOut); @@ -320,7 +321,7 @@ public class MobileSignalController extends SignalController< dataContentDescription = mContext.getString(R.string.data_connection_no_internet); } final boolean dataDisabled = (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED - || mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA) + || (mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA)) && mCurrentState.userSetup; // Show icon in QS when we are connected or data is disabled. @@ -484,6 +485,7 @@ public class MobileSignalController extends SignalController< Log.d(mTag, "updateTelephonySignalStrength: hasService=" + Utils.isInService(mServiceState) + " ss=" + mSignalStrength); } + checkDefaultData(); mCurrentState.connected = Utils.isInService(mServiceState) && mSignalStrength != null; if (mCurrentState.connected) { @@ -541,6 +543,23 @@ public class MobileSignalController extends SignalController< notifyListenersIfNecessary(); } + /** + * If we are controlling the NOT_DEFAULT_DATA icon, check the status of the other one + */ + private void checkDefaultData() { + if (mCurrentState.iconGroup != TelephonyIcons.NOT_DEFAULT_DATA) { + mCurrentState.defaultDataOff = false; + return; + } + + mCurrentState.defaultDataOff = mNetworkController.isDataControllerDisabled(); + } + + void onMobileDataChanged() { + checkDefaultData(); + notifyListenersIfNecessary(); + } + private MobileIconGroup getNr5GIconGroup() { if (mServiceState == null) return null; @@ -617,7 +636,7 @@ public class MobileSignalController extends SignalController< return candidateIconGroup; } - private boolean isDataDisabled() { + boolean isDataDisabled() { return !mPhone.isDataCapable(); } @@ -750,6 +769,7 @@ public class MobileSignalController extends SignalController< boolean isDefault; boolean userSetup; boolean roaming; + boolean defaultDataOff; // Tracks the on/off state of the defaultDataSubscription @Override public void copyFrom(State s) { @@ -765,6 +785,7 @@ public class MobileSignalController extends SignalController< carrierNetworkChangeMode = state.carrierNetworkChangeMode; userSetup = state.userSetup; roaming = state.roaming; + defaultDataOff = state.defaultDataOff; } @Override @@ -781,7 +802,8 @@ public class MobileSignalController extends SignalController< builder.append("airplaneMode=").append(airplaneMode).append(','); builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode) .append(','); - builder.append("userSetup=").append(userSetup); + builder.append("userSetup=").append(userSetup).append(','); + builder.append("defaultDataOff=").append(defaultDataOff); } @Override @@ -796,7 +818,8 @@ public class MobileSignalController extends SignalController< && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode && ((MobileState) o).userSetup == userSetup && ((MobileState) o).isDefault == isDefault - && ((MobileState) o).roaming == roaming; + && ((MobileState) o).roaming == roaming + && ((MobileState) o).defaultDataOff == defaultDataOff; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index bb3742198117..7e1a73208765 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -220,6 +220,7 @@ public class NetworkControllerImpl extends BroadcastReceiver @Override public void onMobileDataEnabled(boolean enabled) { mCallbackHandler.setMobileDataEnabled(enabled); + notifyControllersMobileDataChanged(); } }); mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature, @@ -385,6 +386,22 @@ public class NetworkControllerImpl extends BroadcastReceiver return mMobileSignalControllers.size(); } + boolean isDataControllerDisabled() { + MobileSignalController dataController = getDataController(); + if (dataController == null) { + return false; + } + + return dataController.isDataDisabled(); + } + + private void notifyControllersMobileDataChanged() { + for (int i = 0; i < mMobileSignalControllers.size(); i++) { + MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); + mobileSignalController.onMobileDataChanged(); + } + } + public boolean isEmergencyOnly() { if (mMobileSignalControllers.size() == 0) { // When there are no active subscriptions, determine emengency state from last diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java index 282d28c3b20c..ed0b9d929466 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -235,17 +235,17 @@ public class SmartReplyView extends ViewGroup { * Add smart actions to be shown next to smart replies. Only the actions that fit into the * notification are shown. */ - public List<Button> inflateSmartActions(@NonNull SmartActions smartActions, - SmartReplyController smartReplyController, NotificationEntry entry, - HeadsUpManager headsUpManager, boolean delayOnClickListener) { + public List<Button> inflateSmartActions(Context packageContext, + @NonNull SmartActions smartActions, SmartReplyController smartReplyController, + NotificationEntry entry, HeadsUpManager headsUpManager, boolean delayOnClickListener) { List<Button> buttons = new ArrayList<>(); int numSmartActions = smartActions.actions.size(); for (int n = 0; n < numSmartActions; n++) { Notification.Action action = smartActions.actions.get(n); if (action.actionIntent != null) { buttons.add(inflateActionButton( - this, getContext(), n, smartActions, smartReplyController, entry, - headsUpManager, delayOnClickListener)); + this, getContext(), packageContext, n, smartActions, smartReplyController, + entry, headsUpManager, delayOnClickListener)); } } return buttons; @@ -327,7 +327,7 @@ public class SmartReplyView extends ViewGroup { @VisibleForTesting static Button inflateActionButton(SmartReplyView smartReplyView, Context context, - int actionIndex, SmartActions smartActions, + Context packageContext, int actionIndex, SmartActions smartActions, SmartReplyController smartReplyController, NotificationEntry entry, HeadsUpManager headsUpManager, boolean useDelayedOnClickListener) { Notification.Action action = smartActions.actions.get(actionIndex); @@ -335,7 +335,9 @@ public class SmartReplyView extends ViewGroup { R.layout.smart_action_button, smartReplyView, false); button.setText(action.title); - Drawable iconDrawable = action.getIcon().loadDrawable(context); + // We received the Icon from the application - so use the Context of the application to + // reference icon resources. + Drawable iconDrawable = action.getIcon().loadDrawable(packageContext); // Add the action icon to the Smart Action button. int newIconSize = context.getResources().getDimensionPixelSize( R.dimen.smart_action_button_icon_size); diff --git a/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java new file mode 100644 index 000000000000..a905eba1f0ed --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2019 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.util; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.util.Log; + +import com.android.systemui.R; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +/** + * Simple wrapper around SensorManager customized for the Proximity sensor. + */ +public class ProximitySensor { + private static final String TAG = "ProxSensor"; + private static final boolean DEBUG = false; + + private final Sensor mSensor; + private final AsyncSensorManager mSensorManager; + private final boolean mUsingBrightnessSensor; + private final float mMaxRange; + + private SensorEventListener mSensorEventListener = new SensorEventListener() { + @Override + public synchronized void onSensorChanged(SensorEvent event) { + onSensorEvent(event); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + }; + private boolean mNear; + private List<ProximitySensorListener> mListeners = new ArrayList<>(); + private String mTag = null; + + @Inject + public ProximitySensor(Context context, AsyncSensorManager sensorManager) { + mSensorManager = sensorManager; + Sensor sensor = findBrightnessSensor(context, sensorManager); + + if (sensor == null) { + mUsingBrightnessSensor = false; + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); + } else { + mUsingBrightnessSensor = true; + } + mSensor = sensor; + if (mSensor != null) { + mMaxRange = mSensor.getMaximumRange(); + } else { + mMaxRange = 0; + } + } + + public void setTag(String tag) { + mTag = tag; + } + + private Sensor findBrightnessSensor(Context context, SensorManager sensorManager) { + String sensorType = context.getString(R.string.doze_brightness_sensor_type); + List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL); + Sensor sensor = null; + for (Sensor s : sensorList) { + if (sensorType.equals(s.getStringType())) { + sensor = s; + break; + } + } + + return sensor; + } + + /** + * Returns {@code false} if a Proximity sensor is not available. + */ + public boolean getSensorAvailable() { + return mSensor != null; + } + + /** + * Add a listener. + * + * Registers itself with the {@link SensorManager} if this is the first listener + * added. + */ + public boolean register(ProximitySensorListener listener) { + if (!getSensorAvailable()) { + return false; + } + + logDebug("using brightness sensor? " + mUsingBrightnessSensor); + mListeners.add(listener); + if (mListeners.size() == 1) { + logDebug("registering sensor listener"); + mSensorManager.registerListener( + mSensorEventListener, mSensor, SensorManager.SENSOR_DELAY_GAME); + } + + return true; + } + + /** + * Remove a listener. + * + * If all listeners are removed from an instance of this class, + * it will unregister itself with the SensorManager. + */ + public void unregister(ProximitySensorListener listener) { + mListeners.remove(listener); + if (mListeners.size() == 0) { + logDebug("unregistering sensor listener"); + mSensorManager.unregisterListener(mSensorEventListener); + } + } + + public boolean isNear() { + return getSensorAvailable() && mNear; + } + + private void onSensorEvent(SensorEvent event) { + boolean near = event.values[0] < mMaxRange; + if (mUsingBrightnessSensor) { + near = event.values[0] == 0; + } + mNear = near; + mListeners.forEach(proximitySensorListener -> + proximitySensorListener.onProximitySensorEvent( + new ProximityEvent(mNear, event.timestamp))); + } + + /** Implement to be notified of ProximityEvents. */ + public interface ProximitySensorListener { + /** Called when the ProximitySensor changes. */ + void onProximitySensorEvent(ProximityEvent proximityEvent); + } + + /** + * Returned when the near/far state of a {@link ProximitySensor} changes. + */ + public static class ProximityEvent { + private final boolean mNear; + private final long mTimestampNs; + + public ProximityEvent(boolean near, long timestampNs) { + mNear = near; + mTimestampNs = timestampNs; + } + + public boolean getNear() { + return mNear; + } + + public long getTimestampNs() { + return mTimestampNs; + } + } + + private void logDebug(String msg) { + if (DEBUG) { + Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg); + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java deleted file mode 100644 index 72a457e9bbbe..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2019 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; - -import static com.android.systemui.ForegroundServiceNotificationListener.ForegroundServiceLifetimeExtender.MIN_FGS_TIME_MS; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.app.Notification; -import android.service.notification.StatusBarNotification; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.systemui.statusbar.notification.collection.NotificationEntry; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class ForegroundServiceNotificationListenerTest extends SysuiTestCase { - private ForegroundServiceNotificationListener.ForegroundServiceLifetimeExtender mExtender = - new ForegroundServiceNotificationListener.ForegroundServiceLifetimeExtender(); - private StatusBarNotification mSbn; - private NotificationEntry mEntry; - private Notification mNotif; - - @Before - public void setup() { - mNotif = new Notification.Builder(mContext, "") - .setSmallIcon(R.drawable.ic_person) - .setContentTitle("Title") - .setContentText("Text") - .build(); - - mSbn = mock(StatusBarNotification.class); - when(mSbn.getNotification()).thenReturn(mNotif); - - mEntry = new NotificationEntry(mSbn); - } - - /** - * ForegroundServiceLifetimeExtenderTest - */ - @Test - public void testShouldExtendLifetime_should_foreground() { - // Extend the lifetime of a FGS notification iff it has not been visible - // for the minimum time - mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE; - when(mSbn.getPostTime()).thenReturn(System.currentTimeMillis()); - assertTrue(mExtender.shouldExtendLifetime(mEntry)); - } - - @Test - public void testShouldExtendLifetime_shouldNot_foreground() { - mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE; - when(mSbn.getPostTime()).thenReturn(System.currentTimeMillis() - MIN_FGS_TIME_MS - 1); - assertFalse(mExtender.shouldExtendLifetime(mEntry)); - } - - @Test - public void testShouldExtendLifetime_shouldNot_notForeground() { - mNotif.flags = 0; - when(mSbn.getPostTime()).thenReturn(System.currentTimeMillis() - MIN_FGS_TIME_MS - 1); - assertFalse(mExtender.shouldExtendLifetime(mEntry)); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleLikeHomeBehaviorTest.java b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleLikeHomeBehaviorTest.java index 2aa866e2c179..21ef640d6bf6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleLikeHomeBehaviorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleLikeHomeBehaviorTest.java @@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.shared.system.QuickStepContract; @@ -47,6 +48,7 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { private AssistHandleLikeHomeBehavior mAssistHandleLikeHomeBehavior; + @Mock private StatusBarStateController mMockStatusBarStateController; @Mock private WakefulnessLifecycle mMockWakefulnessLifecycle; @Mock private OverviewProxyService mMockOverviewProxyService; @Mock private AssistHandleCallbacks mMockAssistHandleCallbacks; @@ -55,7 +57,9 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { public void setup() { MockitoAnnotations.initMocks(this); mAssistHandleLikeHomeBehavior = new AssistHandleLikeHomeBehavior( - () -> mMockWakefulnessLifecycle, () -> mMockOverviewProxyService); + () -> mMockStatusBarStateController, + () -> mMockWakefulnessLifecycle, + () -> mMockOverviewProxyService); } @Test @@ -66,6 +70,9 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks); // Assert + verify(mMockStatusBarStateController).isDozing(); + verify(mMockStatusBarStateController).addCallback( + any(StatusBarStateController.StateListener.class)); verify(mMockWakefulnessLifecycle).getWakefulness(); verify(mMockWakefulnessLifecycle).addObserver(any(WakefulnessLifecycle.Observer.class)); verify(mMockOverviewProxyService).addCallback(any( @@ -74,8 +81,9 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { } @Test - public void onModeActivated_showsHandlesWhenAwake() { + public void onModeActivated_showsHandlesWhenFullyAwake() { // Arrange + when(mMockStatusBarStateController.isDozing()).thenReturn(false); when(mMockWakefulnessLifecycle.getWakefulness()) .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE); @@ -90,6 +98,7 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { @Test public void onModeActivated_hidesHandlesWhenNotAwake() { // Arrange + when(mMockStatusBarStateController.isDozing()).thenReturn(true); when(mMockWakefulnessLifecycle.getWakefulness()) .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP); @@ -102,72 +111,139 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { } @Test + public void onModeActivated_hidesHandlesWhenDozing() { + // Arrange + when(mMockStatusBarStateController.isDozing()).thenReturn(true); + when(mMockWakefulnessLifecycle.getWakefulness()) + .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE); + + // Act + mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks); + + // Assert + verify(mMockAssistHandleCallbacks).hide(); + verifyNoMoreInteractions(mMockAssistHandleCallbacks); + } + + @Test public void onModeDeactivated_stopsObserving() { // Arrange mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks); + ArgumentCaptor<StatusBarStateController.StateListener> stateListener = + ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); ArgumentCaptor<WakefulnessLifecycle.Observer> observer = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class); ArgumentCaptor<OverviewProxyService.OverviewProxyListener> overviewProxyListener = ArgumentCaptor.forClass(OverviewProxyService.OverviewProxyListener.class); + verify(mMockStatusBarStateController).addCallback(stateListener.capture()); verify(mMockWakefulnessLifecycle).addObserver(observer.capture()); verify(mMockOverviewProxyService).addCallback(overviewProxyListener.capture()); - reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + reset( + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); // Act mAssistHandleLikeHomeBehavior.onModeDeactivated(); // Assert + verify(mMockStatusBarStateController).removeCallback(eq(stateListener.getValue())); verify(mMockWakefulnessLifecycle).removeObserver(eq(observer.getValue())); verify(mMockOverviewProxyService).removeCallback(eq(overviewProxyListener.getValue())); verifyNoMoreInteractions( - mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); } @Test public void onAssistantGesturePerformed_doesNothing() { // Arrange mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks); - reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + reset( + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); // Act mAssistHandleLikeHomeBehavior.onAssistantGesturePerformed(); // Assert verifyNoMoreInteractions( - mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); } @Test public void onAssistHandlesRequested_doesNothing() { // Arrange mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks); - reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + reset( + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); // Act mAssistHandleLikeHomeBehavior.onAssistHandlesRequested(); // Assert verifyNoMoreInteractions( - mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); } @Test - public void onWake_handlesShow() { + public void onBothAwakeAndUnDoze_handlesShow() { // Arrange + when(mMockStatusBarStateController.isDozing()).thenReturn(true); when(mMockWakefulnessLifecycle.getWakefulness()) .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP); + ArgumentCaptor<StatusBarStateController.StateListener> stateListener = + ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); ArgumentCaptor<WakefulnessLifecycle.Observer> observer = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class); mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks); + verify(mMockStatusBarStateController).addCallback(stateListener.capture()); verify(mMockWakefulnessLifecycle).addObserver(observer.capture()); - reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + reset( + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); // Act - observer.getValue().onStartedWakingUp(); + observer.getValue().onFinishedWakingUp(); // Assert + verify(mMockAssistHandleCallbacks).hide(); verifyNoMoreInteractions( - mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); + + // Arrange + observer.getValue().onFinishedGoingToSleep(); + reset(mMockAssistHandleCallbacks); + + // Act + stateListener.getValue().onDozingChanged(false); + + // Assert + verify(mMockAssistHandleCallbacks).hide(); + verifyNoMoreInteractions( + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); // Act observer.getValue().onFinishedWakingUp(); @@ -175,19 +251,30 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { // Assert verify(mMockAssistHandleCallbacks).showAndStay(); verifyNoMoreInteractions( - mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); } @Test - public void onSleep_handlesHide() { + public void onSleepOrDoze_handlesHide() { // Arrange + when(mMockStatusBarStateController.isDozing()).thenReturn(false); when(mMockWakefulnessLifecycle.getWakefulness()) .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE); + ArgumentCaptor<StatusBarStateController.StateListener> stateListener = + ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); ArgumentCaptor<WakefulnessLifecycle.Observer> observer = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class); mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks); + verify(mMockStatusBarStateController).addCallback(stateListener.capture()); verify(mMockWakefulnessLifecycle).addObserver(observer.capture()); - reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + reset( + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); // Act observer.getValue().onStartedGoingToSleep(); @@ -195,26 +282,42 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { // Assert verify(mMockAssistHandleCallbacks).hide(); verifyNoMoreInteractions( - mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); + + // Arrange + observer.getValue().onFinishedWakingUp(); + reset(mMockAssistHandleCallbacks); // Act - observer.getValue().onFinishedGoingToSleep(); + stateListener.getValue().onDozingChanged(true); // Assert + verify(mMockAssistHandleCallbacks).hide(); verifyNoMoreInteractions( - mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); } @Test public void onHomeHandleHide_handlesHide() { // Arrange + when(mMockStatusBarStateController.isDozing()).thenReturn(false); when(mMockWakefulnessLifecycle.getWakefulness()) .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE); ArgumentCaptor<OverviewProxyService.OverviewProxyListener> sysUiStateCallback = ArgumentCaptor.forClass(OverviewProxyService.OverviewProxyListener.class); mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks); verify(mMockOverviewProxyService).addCallback(sysUiStateCallback.capture()); - reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + reset( + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); // Act sysUiStateCallback.getValue().onSystemUiStateChanged( @@ -223,12 +326,16 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { // Assert verify(mMockAssistHandleCallbacks).hide(); verifyNoMoreInteractions( - mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); } @Test public void onHomeHandleUnhide_handlesShow() { // Arrange + when(mMockStatusBarStateController.isDozing()).thenReturn(false); when(mMockWakefulnessLifecycle.getWakefulness()) .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE); ArgumentCaptor<OverviewProxyService.OverviewProxyListener> sysUiStateCallback = @@ -237,7 +344,11 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { verify(mMockOverviewProxyService).addCallback(sysUiStateCallback.capture()); sysUiStateCallback.getValue().onSystemUiStateChanged( QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN); - reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + reset( + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); // Act sysUiStateCallback.getValue().onSystemUiStateChanged( @@ -246,6 +357,9 @@ public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase { // Assert verify(mMockAssistHandleCallbacks).showAndStay(); verifyNoMoreInteractions( - mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks); + mMockStatusBarStateController, + mMockWakefulnessLifecycle, + mMockOverviewProxyService, + mMockAssistHandleCallbacks); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java index 7ea6493da83d..32cf8429cf62 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java @@ -31,6 +31,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.brightline.BrightLineFalsingManager; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.util.ProximitySensor; import org.junit.After; import org.junit.Before; @@ -43,8 +44,10 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class FalsingManagerProxyTest extends SysuiTestCase { - @Mock + @Mock(stubOnly = true) PluginManager mPluginManager; + @Mock(stubOnly = true) + ProximitySensor mProximitySensor; private boolean mDefaultConfigValue; private Handler mHandler; private TestableLooper mTestableLooper; @@ -69,7 +72,8 @@ public class FalsingManagerProxyTest extends SysuiTestCase { @Test public void test_brightLineFalsingManagerDisabled() { - FalsingManagerProxy proxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler); + FalsingManagerProxy proxy = new FalsingManagerProxy( + getContext(), mPluginManager, mHandler, mProximitySensor); assertThat(proxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class)); } @@ -78,14 +82,16 @@ public class FalsingManagerProxyTest extends SysuiTestCase { public void test_brightLineFalsingManagerEnabled() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, "true", false); - FalsingManagerProxy proxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler); + FalsingManagerProxy proxy = new FalsingManagerProxy( + getContext(), mPluginManager, mHandler, mProximitySensor); assertThat(proxy.getInternalFalsingManager(), instanceOf(BrightLineFalsingManager.class)); } @Test public void test_brightLineFalsingManagerToggled() { - FalsingManagerProxy proxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler); + FalsingManagerProxy proxy = new FalsingManagerProxy( + getContext(), mPluginManager, mHandler, mProximitySensor); assertThat(proxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class)); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java index a6cabbf49458..49ba30272c70 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java @@ -23,24 +23,21 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.when; -import android.hardware.Sensor; -import android.hardware.SensorEvent; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.MotionEvent; import androidx.test.filters.SmallTest; +import com.android.systemui.util.ProximitySensor; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import java.lang.reflect.Field; - @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -78,8 +75,8 @@ public class ProximityClassifierTest extends ClassifierTest { @Test public void testPass_mostlyUncovered() { touchDown(); - mClassifier.onSensorEvent(createSensorEvent(true, 1)); - mClassifier.onSensorEvent(createSensorEvent(false, 2)); + mClassifier.onProximityEvent(createSensorEvent(true, 1)); + mClassifier.onProximityEvent(createSensorEvent(false, 2)); touchUp(20); assertThat(mClassifier.isFalseTouch(), is(false)); } @@ -88,8 +85,8 @@ public class ProximityClassifierTest extends ClassifierTest { public void testPass_quickSettings() { touchDown(); when(mDataProvider.getInteractionType()).thenReturn(QUICK_SETTINGS); - mClassifier.onSensorEvent(createSensorEvent(true, 1)); - mClassifier.onSensorEvent(createSensorEvent(false, 11)); + mClassifier.onProximityEvent(createSensorEvent(true, 1)); + mClassifier.onProximityEvent(createSensorEvent(false, 11)); touchUp(10); assertThat(mClassifier.isFalseTouch(), is(false)); } @@ -97,8 +94,8 @@ public class ProximityClassifierTest extends ClassifierTest { @Test public void testFail_covered() { touchDown(); - mClassifier.onSensorEvent(createSensorEvent(true, 1)); - mClassifier.onSensorEvent(createSensorEvent(false, 11)); + mClassifier.onProximityEvent(createSensorEvent(true, 1)); + mClassifier.onProximityEvent(createSensorEvent(false, 11)); touchUp(10); assertThat(mClassifier.isFalseTouch(), is(true)); } @@ -106,10 +103,10 @@ public class ProximityClassifierTest extends ClassifierTest { @Test public void testFail_mostlyCovered() { touchDown(); - mClassifier.onSensorEvent(createSensorEvent(true, 1)); - mClassifier.onSensorEvent(createSensorEvent(true, 95)); - mClassifier.onSensorEvent(createSensorEvent(true, 96)); - mClassifier.onSensorEvent(createSensorEvent(false, 100)); + mClassifier.onProximityEvent(createSensorEvent(true, 1)); + mClassifier.onProximityEvent(createSensorEvent(true, 95)); + mClassifier.onProximityEvent(createSensorEvent(true, 96)); + mClassifier.onProximityEvent(createSensorEvent(false, 100)); touchUp(100); assertThat(mClassifier.isFalseTouch(), is(true)); } @@ -117,8 +114,8 @@ public class ProximityClassifierTest extends ClassifierTest { @Test public void testPass_coveredWithLongSwipe() { touchDown(); - mClassifier.onSensorEvent(createSensorEvent(true, 1)); - mClassifier.onSensorEvent(createSensorEvent(false, 11)); + mClassifier.onProximityEvent(createSensorEvent(true, 1)); + mClassifier.onProximityEvent(createSensorEvent(false, 11)); touchUp(10); when(mDistanceClassifier.isLongSwipe()).thenReturn(true); assertThat(mClassifier.isFalseTouch(), is(false)); @@ -139,26 +136,7 @@ public class ProximityClassifierTest extends ClassifierTest { motionEvent.recycle(); } - private SensorEvent createSensorEvent(boolean covered, long timestampMs) { - SensorEvent sensorEvent = Mockito.mock(SensorEvent.class); - Sensor sensor = Mockito.mock(Sensor.class); - when(sensor.getType()).thenReturn(Sensor.TYPE_PROXIMITY); - when(sensor.getMaximumRange()).thenReturn(1f); - sensorEvent.sensor = sensor; - sensorEvent.timestamp = timestampMs * NS_PER_MS; - try { - Field valuesField = SensorEvent.class.getField("values"); - valuesField.setAccessible(true); - float[] sensorValue = {covered ? 0 : 1}; - try { - valuesField.set(sensorEvent, sensorValue); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } - - return sensorEvent; + private ProximitySensor.ProximityEvent createSensorEvent(boolean covered, long timestampMs) { + return new ProximitySensor.ProximityEvent(covered, timestampMs * NS_PER_MS); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 0334d49ce9df..f94779d6d5ca 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -129,7 +129,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mKeyguardBypassController); PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator, mKeyguardBypassController, mHeadsUpManager, - mock(NotificationRoundnessManager.class)); + mock(NotificationRoundnessManager.class), mStatusBarStateController); mNotificationPanelView = new TestableNotificationPanelView(coordinator, expansionHandler, mKeyguardBypassController); mNotificationPanelView.setHeadsUpManager(mHeadsUpManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index c5d4019252ff..e05ad09deebf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -241,7 +241,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test - public void transitionToPulsing() { + public void transitionToPulsing_withFrontAlphaUpdates() { // Pre-condition // Need to go to AoD first because PULSING doesn't change // the back scrim opacity - otherwise it would hide AoD wallpapers. @@ -265,11 +265,22 @@ public class ScrimControllerTest extends SysuiTestCase { true /* behind */, false /* bubble */); + // ... and when ambient goes dark, front scrim should be semi-transparent + mScrimController.setAodFrontScrimAlpha(0.5f); + mScrimController.finishAnimationsImmediately(); + // Front scrim should be semi-transparent + assertScrimAlpha(SEMI_TRANSPARENT /* front */, + OPAQUE /* back */, + TRANSPARENT /* bubble */); + mScrimController.setWakeLockScreenSensorActive(true); mScrimController.finishAnimationsImmediately(); - assertScrimAlpha(TRANSPARENT /* front */, + assertScrimAlpha(SEMI_TRANSPARENT /* front */, SEMI_TRANSPARENT /* back */, TRANSPARENT /* bubble */); + + // Reset value since enums are static. + mScrimController.setAodFrontScrimAlpha(0f); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index 3ddfbdac6db8..aa4723acba62 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -147,7 +147,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { } @Test - public void testNoInternetIcon_withoutDefaultSub() { + public void testNonDefaultSIM_showsFullSignal_connected() { setupNetworkController(); when(mMockTm.isDataCapable()).thenReturn(false); setupDefaultSignal(); @@ -158,11 +158,11 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { // Verify that a SignalDrawable with a cut out is used to display data disabled. verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, 0, true, DEFAULT_QS_SIGNAL_STRENGTH, 0, false, - false, true, NOT_DEFAULT_DATA_STRING); + false, false, NOT_DEFAULT_DATA_STRING); } @Test - public void testDataDisabledIcon_withoutDefaultSub() { + public void testNonDefaultSIM_showsFullSignal_disconnected() { setupNetworkController(); when(mMockTm.isDataCapable()).thenReturn(false); setupDefaultSignal(); @@ -173,7 +173,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { // Verify that a SignalDrawable with a cut out is used to display data disabled. verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, 0, true, DEFAULT_QS_SIGNAL_STRENGTH, 0, false, - false, true, NOT_DEFAULT_DATA_STRING); + false, false, NOT_DEFAULT_DATA_STRING); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java index 0cb575483466..6be708177e89 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java @@ -494,6 +494,7 @@ public class SmartReplyViewTest extends SysuiTestCase { private void setSmartActions(String[] actionTitles, boolean useDelayedOnClickListener) { mView.resetSmartSuggestions(mContainer); List<Button> actions = mView.inflateSmartActions( + getContext(), new SmartReplyView.SmartActions(createActions(actionTitles), false), mLogger, mEntry, @@ -514,6 +515,7 @@ public class SmartReplyViewTest extends SysuiTestCase { List<Button> smartSuggestions = inflateSmartReplies(choices, fromAssistant, useDelayedOnClickListener); smartSuggestions.addAll(mView.inflateSmartActions( + getContext(), new SmartReplyView.SmartActions(createActions(actionTitles), fromAssistant), mLogger, mEntry, @@ -860,7 +862,7 @@ public class SmartReplyViewTest extends SysuiTestCase { } private Button inflateActionButton(Notification.Action action) { - return SmartReplyView.inflateActionButton(mView, getContext(), 0, + return SmartReplyView.inflateActionButton(mView, getContext(), getContext(), 0, new SmartReplyView.SmartActions(Collections.singletonList(action), false), mLogger, mEntry, mHeadsUpManager, true /* useDelayedOnClickListener */); } diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 8ad24894a1b9..fbf6ca52f11c 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -1792,6 +1792,25 @@ message ExperimentValues { // Indicates if we are logging LinkSpeedCount in metrics optional bool link_speed_counts_logging_enabled = 4; + + // Duration for evaluating Wifi condition to trigger a data stall + // measured in milliseconds + optional int32 data_stall_duration_ms = 5; + + // Threshold of Tx throughput below which to trigger a data stall + // measured in Kbps + optional int32 data_stall_tx_tput_thr_kbps = 6; + + // Threshold of Rx throughput below which to trigger a data stall + // measured in Kbps + optional int32 data_stall_rx_tput_thr_kbps = 7; + + // Threshold of Tx packet error rate above which to trigger a data stall + // in percentage + optional int32 data_stall_tx_per_thr = 8; + + // Threshold of CCA level above which to trigger a data stall in percentage + optional int32 data_stall_cca_level_thr = 9; } message WifiIsUnusableEvent { diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index d260985190f7..87991beefcee 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2407,7 +2407,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Update the view states first... mCurrentViewId = viewState.id; - viewState.setCurrentValue(value); + if (value != null) { + viewState.setCurrentValue(value); + } if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) { if (sDebug) Slog.d(TAG, "Ignoring VIEW_ENTERED on URL BAR (id=" + id + ")"); diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 52a4218238e7..2ab46e65e77f 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -2737,7 +2737,9 @@ public class DeviceIdleController extends SystemService resetIdleManagementLocked(); // Wait a small amount of time in case something (eg: background service from // recently closed app) needs to finish running. - scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false); + // Use a non-wakeup alarm for going into quick doze in case an AlarmClock alarm + // is scheduled soon. The non-wakeup alarm will be delayed by at most 2 minutes. + scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false, false); EventLogTags.writeDeviceIdle(mState, "no activity"); } else if (mState == STATE_ACTIVE) { mState = STATE_INACTIVE; @@ -3362,6 +3364,10 @@ public class DeviceIdleController extends SystemService } void scheduleAlarmLocked(long delay, boolean idleUntil) { + scheduleAlarmLocked(delay, idleUntil, true); + } + + private void scheduleAlarmLocked(long delay, boolean idleUntil, boolean useWakeupAlarm) { if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")"); if (mUseMotionSensor && mMotionSensor == null @@ -3377,12 +3383,14 @@ public class DeviceIdleController extends SystemService // can continue until the user interacts with the device. return; } + final int alarmType = useWakeupAlarm + ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME; mNextAlarmTime = SystemClock.elapsedRealtime() + delay; if (idleUntil) { - mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.setIdleUntil(alarmType, mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); } else { - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.set(alarmType, mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); } } diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java index 1891ba9b1742..6bc1a570b7c0 100644 --- a/services/core/java/com/android/server/MountServiceIdler.java +++ b/services/core/java/com/android/server/MountServiceIdler.java @@ -27,6 +27,7 @@ import android.content.ComponentName; import android.content.Context; import android.os.RemoteException; import android.util.Slog; +import java.util.concurrent.TimeUnit; public class MountServiceIdler extends JobService { private static final String TAG = "MountServiceIdler"; @@ -48,7 +49,7 @@ public class MountServiceIdler extends JobService { mStarted = false; } } - // ... and try again tomorrow + // ... and try again right away or tomorrow scheduleIdlePass(MountServiceIdler.this); } }; @@ -98,24 +99,32 @@ public class MountServiceIdler extends JobService { public static void scheduleIdlePass(Context context) { JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - Calendar calendar = tomorrowMidnight(); - final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis(); + final long today3AM = offsetFromTodayMidnight(0, 3).getTimeInMillis(); + final long today4AM = offsetFromTodayMidnight(0, 4).getTimeInMillis(); + final long tomorrow3AM = offsetFromTodayMidnight(1, 3).getTimeInMillis(); + + long nextScheduleTime; + if (System.currentTimeMillis() > today3AM && System.currentTimeMillis() < today4AM) { + nextScheduleTime = TimeUnit.SECONDS.toMillis(10); + } else { + nextScheduleTime = tomorrow3AM - System.currentTimeMillis(); // 3AM tomorrow + } JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService); builder.setRequiresDeviceIdle(true); - builder.setRequiresCharging(true); - builder.setMinimumLatency(timeToMidnight); + builder.setRequiresBatteryNotLow(true); + builder.setMinimumLatency(nextScheduleTime); tm.schedule(builder.build()); } - private static Calendar tomorrowMidnight() { + private static Calendar offsetFromTodayMidnight(int nDays, int nHours) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); - calendar.set(Calendar.HOUR_OF_DAY, 3); + calendar.set(Calendar.HOUR_OF_DAY, nHours); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); - calendar.add(Calendar.DAY_OF_MONTH, 1); + calendar.add(Calendar.DAY_OF_MONTH, nDays); return calendar; } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ee18b8974bac..6a9511f24891 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5255,11 +5255,14 @@ public class ActivityManagerService extends IActivityManager.Stub // Inform checkpointing systems of success try { + // This line is needed to CTS test for the correct exception handling + // See b/138952436#comment36 for context + Slog.i(TAG, "About to commit checkpoint"); IStorageManager storageManager = PackageHelper.getStorageManager(); storageManager.commitChanges(); } catch (Exception e) { PowerManager pm = (PowerManager) - mContext.getSystemService(Context.POWER_SERVICE); + mInjector.getContext().getSystemService(Context.POWER_SERVICE); pm.reboot("Checkpoint commit failed"); } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index b44904135736..48d0073425a8 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -510,6 +510,10 @@ public class AppOpsService extends IAppOpsService.Stub { private void updateProxyState(long key, int proxyUid, @Nullable String proxyPackageName) { + if (proxyUid == Process.INVALID_UID) { + return; + } + if (mProxyUids == null) { mProxyUids = new LongSparseLongArray(); } diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index fbe2589bea2a..29c4bad2e172 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -130,6 +130,11 @@ public class PermissionMonitor { } @Override + public void onPackageChanged(@NonNull String packageName, int uid) { + sendPackagePermissionsForUid(uid, getPermissionForUid(uid)); + } + + @Override public void onPackageRemoved(String packageName, int uid) { sendPackagePermissionsForUid(uid, getPermissionForUid(uid)); } diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 73d160d8c444..24581a247216 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -455,7 +455,20 @@ public class Tethering extends BaseNetworkObserver { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { - ((BluetoothPan) proxy).setBluetoothTethering(enable); + // Clear identify is fine because caller already pass tethering permission at + // ConnectivityService#startTethering()(or stopTethering) before the control comes + // here. Bluetooth will check tethering permission again that there is + // Context#getOpPackageName() under BluetoothPan#setBluetoothTethering() to get + // caller's package name for permission check. + // Calling BluetoothPan#setBluetoothTethering() here means the package name always + // be system server. If calling identity is not cleared, that package's uid might + // not match calling uid and end up in permission denied. + final long identityToken = Binder.clearCallingIdentity(); + try { + ((BluetoothPan) proxy).setBluetoothTethering(enable); + } finally { + Binder.restoreCallingIdentity(identityToken); + } // TODO: Enabling bluetooth tethering can fail asynchronously here. // We should figure out a way to bubble up that failure instead of sending success. final int result = (((BluetoothPan) proxy).isTetheringOn() == enable) diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java index 7fb5b191a9b0..0bf43b6d1b9c 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java @@ -609,6 +609,9 @@ public final class ColorDisplayService extends SystemService { @Override public void onAnimationEnd(Animator animator) { + Slog.d(TAG, tintController.getClass().getSimpleName() + + " Animation cancelled: " + mIsCancelled + + " to matrix: " + TintController.matrixToString(to, 16)); if (!mIsCancelled) { // Ensure final color matrix is set at the end of the animation. If the // animation is cancelled then don't set the final color matrix so the new @@ -1314,8 +1317,10 @@ public final class ColorDisplayService extends SystemService { * Reset the CCT value for the display white balance transform to its default value. */ public boolean resetDisplayWhiteBalanceColorTemperature() { - return setDisplayWhiteBalanceColorTemperature(getContext().getResources() - .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault)); + int temperatureDefault = getContext().getResources() + .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault); + Slog.d(TAG, "resetDisplayWhiteBalanceColorTemperature: " + temperatureDefault); + return setDisplayWhiteBalanceColorTemperature(temperatureDefault); } /** diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java index d2c6cd9f1007..3f1c222ab520 100644 --- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java +++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java @@ -149,8 +149,6 @@ final class DisplayWhiteBalanceTintController extends TintController { cct = mTemperatureMax; } - Slog.d(ColorDisplayService.TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct); - synchronized (mLock) { mCurrentColorTemperature = cct; @@ -185,6 +183,9 @@ final class DisplayWhiteBalanceTintController extends TintController { java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3); java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3); } + + Slog.d(ColorDisplayService.TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct + + " matrix = " + matrixToString(mMatrixDisplayWhiteBalance, 16)); } @Override @@ -225,28 +226,6 @@ final class DisplayWhiteBalanceTintController extends TintController { } } - /** - * Format a given matrix into a string. - * - * @param matrix the matrix to format - * @param columns number of columns in the matrix - */ - private String matrixToString(float[] matrix, int columns) { - if (matrix == null || columns <= 0) { - Slog.e(ColorDisplayService.TAG, "Invalid arguments when formatting matrix to string"); - return ""; - } - - final StringBuilder sb = new StringBuilder(""); - for (int i = 0; i < matrix.length; i++) { - if (i % columns == 0) { - sb.append("\n "); - } - sb.append(String.format("%9.6f", matrix[i])); - } - return sb.toString(); - } - private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) { return new ColorSpace.Rgb( "Display Color Space", diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java index b291c645027a..8d8b9b2af04e 100644 --- a/services/core/java/com/android/server/display/color/TintController.java +++ b/services/core/java/com/android/server/display/color/TintController.java @@ -18,6 +18,7 @@ package com.android.server.display.color; import android.animation.ValueAnimator; import android.content.Context; +import android.util.Slog; import java.io.PrintWriter; @@ -95,4 +96,29 @@ abstract class TintController { * Returns whether or not this transform type is available on this device. */ public abstract boolean isAvailable(Context context); + + /** + * Format a given matrix into a string. + * + * @param matrix the matrix to format + * @param columns number of columns in the matrix + */ + static String matrixToString(float[] matrix, int columns) { + if (matrix == null || columns <= 0) { + Slog.e(ColorDisplayService.TAG, "Invalid arguments when formatting matrix to string," + + " matrix is null: " + (matrix == null) + + " columns: " + columns); + return ""; + } + + final StringBuilder sb = new StringBuilder(""); + for (int i = 0; i < matrix.length; i++) { + if (i % columns == 0) { + sb.append("\n "); + } + sb.append(String.format("%9.6f", matrix[i])); + } + return sb.toString(); + } + } diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java index 02ec10e2d49d..7b1f4c3222f3 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java @@ -95,6 +95,11 @@ public class DisplayWhiteBalanceController implements // A piecewise linear relationship between high light brightness and high light bias. private Spline.LinearSpline mHighLightAmbientBrightnessToBiasSpline; + private float mLatestAmbientColorTemperature; + private float mLatestAmbientBrightness; + private float mLatestLowLightBias; + private float mLatestHighLightBias; + /** * @param brightnessSensor * The sensor used to detect changes in the ambient brightness. @@ -348,6 +353,7 @@ public class DisplayWhiteBalanceController implements public void updateAmbientColorTemperature() { final long time = System.currentTimeMillis(); float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time); + mLatestAmbientColorTemperature = ambientColorTemperature; if (mAmbientToDisplayColorTemperatureSpline != null && ambientColorTemperature != -1.0f) { ambientColorTemperature = @@ -355,6 +361,7 @@ public class DisplayWhiteBalanceController implements } float ambientBrightness = mBrightnessFilter.getEstimate(time); + mLatestAmbientBrightness = ambientBrightness; if (ambientColorTemperature != -1.0f && mLowLightAmbientBrightnessToBiasSpline != null) { @@ -362,6 +369,7 @@ public class DisplayWhiteBalanceController implements ambientColorTemperature = bias * ambientColorTemperature + (1.0f - bias) * mLowLightAmbientColorTemperature; + mLatestLowLightBias = bias; } if (ambientColorTemperature != -1.0f && mHighLightAmbientBrightnessToBiasSpline != null) { @@ -369,6 +377,7 @@ public class DisplayWhiteBalanceController implements ambientColorTemperature = (1.0f - bias) * ambientColorTemperature + bias * mHighLightAmbientColorTemperature; + mLatestHighLightBias = bias; } if (mAmbientColorTemperatureOverride != -1.0f) { @@ -426,6 +435,11 @@ public class DisplayWhiteBalanceController implements } mPendingAmbientColorTemperature = -1.0f; mAmbientColorTemperatureHistory.add(mAmbientColorTemperature); + Slog.d(TAG, "Display cct: " + mAmbientColorTemperature + + " Latest ambient cct: " + mLatestAmbientColorTemperature + + " Latest ambient lux: " + mLatestAmbientBrightness + + " Latest low light bias: " + mLatestLowLightBias + + " Latest high light bias: " + mLatestHighLightBias); mColorDisplayServiceInternal.setDisplayWhiteBalanceColorTemperature( (int) mAmbientColorTemperature); mLastAmbientColorTemperature = mAmbientColorTemperature; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 3eb442f9bdda..c8d068243788 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -5343,16 +5343,8 @@ public class NotificationManagerService extends SystemService { } synchronized (mNotificationLock) { - // If the notification is currently enqueued, repost this runnable so it has a - // chance to notify listeners - if ((findNotificationByListLocked(mEnqueuedNotifications, mPkg, mTag, mId, mUserId)) - != null) { - mHandler.post(this); - return; - } - // Look for the notification in the posted list, since we already checked enqueued. - NotificationRecord r = - findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId); + // Look for the notification, searching both the posted and enqueued lists. + NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId); if (r != null) { // The notification was found, check if it should be removed. diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 9b6333d7bef4..3464cab99d93 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -443,45 +443,39 @@ public class LauncherAppsService extends SystemService { if (isManagedProfileAdmin(user, appInfo.packageName)) { return false; } - // If app does not have any components or any permissions, the app can legitimately - // have no icon so we do not show the synthetic activity. - return hasComponentsAndRequestsPermissions(appInfo.packageName); - } - - private boolean hasComponentsAndRequestsPermissions(@NonNull String packageName) { final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); - final PackageParser.Package pkg = pmInt.getPackage(packageName); + final PackageParser.Package pkg = pmInt.getPackage(appInfo.packageName); if (pkg == null) { // Should not happen, but we shouldn't be failing if it does return false; } - if (ArrayUtils.isEmpty(pkg.requestedPermissions)) { - return false; - } - if (!hasApplicationDeclaredActivities(pkg) - && ArrayUtils.isEmpty(pkg.receivers) - && ArrayUtils.isEmpty(pkg.providers) - && ArrayUtils.isEmpty(pkg.services)) { - return false; - } - return true; + // If app does not have any default enabled launcher activity or any permissions, + // the app can legitimately have no icon so we do not show the synthetic activity. + return requestsPermissions(pkg) && hasDefaultEnableLauncherActivity( + appInfo.packageName); } - private boolean hasApplicationDeclaredActivities(@NonNull PackageParser.Package pkg) { - if (pkg.activities == null) { - return false; - } - if (ArrayUtils.isEmpty(pkg.activities)) { - return false; - } - // If it only contains synthetic AppDetailsActivity only, it means application does - // not have actual activity declared in manifest. - if (pkg.activities.size() == 1 && PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals( - pkg.activities.get(0).className)) { - return false; + private boolean requestsPermissions(@NonNull PackageParser.Package pkg) { + return !ArrayUtils.isEmpty(pkg.requestedPermissions); + } + + private boolean hasDefaultEnableLauncherActivity(@NonNull String packageName) { + final PackageManagerInternal pmInt = + LocalServices.getService(PackageManagerInternal.class); + final Intent matchIntent = new Intent(Intent.ACTION_MAIN); + matchIntent.addCategory(Intent.CATEGORY_LAUNCHER); + matchIntent.setPackage(packageName); + final List<ResolveInfo> infoList = pmInt.queryIntentActivities(matchIntent, + PackageManager.MATCH_DISABLED_COMPONENTS, Binder.getCallingUid(), + getCallingUserId()); + final int size = infoList.size(); + for (int i = 0; i < size; i++) { + if (infoList.get(i).activityInfo.enabled) { + return true; + } } - return true; + return false; } private boolean isManagedProfileAdmin(UserHandle user, String packageName) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 723579614cd3..8bea9169b031 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -20881,7 +20881,7 @@ public class PackageManagerService extends IPackageManager.Stub public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) { UserManagerService ums = UserManagerService.getInstance(); - if (ums != null) { + if (ums != null && !sessionInfo.isStaged()) { final UserInfo parent = ums.getProfileParent(userId); final int launcherUid = (parent != null) ? parent.id : userId; final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid); diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 4550446f88c5..ecf66861a401 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -190,6 +190,7 @@ public final class DefaultPermissionGrantPolicy { static { STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE); STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION); } private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1; diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index aa49ba62f48b..e1b3e4d6fbcf 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -542,6 +542,10 @@ public final class PowerManagerService extends SystemService // True if we in the process of performing a forceSuspend private boolean mForceSuspendActive; + // Transition to Doze is in progress. We have transitioned to WAKEFULNESS_DOZING, + // but the DreamService has not yet been told to start (it's an async process). + private boolean mDozeStartInProgress; + private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver { @Override public void onUserSwitching(int newUserId) throws RemoteException {} @@ -1514,6 +1518,7 @@ public final class PowerManagerService extends SystemService mLastSleepTime = eventTime; mLastSleepReason = reason; mSandmanSummoned = true; + mDozeStartInProgress = true; setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime); // Report the number of wake locks that will be cleared by going to sleep. @@ -1601,6 +1606,10 @@ public final class PowerManagerService extends SystemService mWakefulness = wakefulness; mWakefulnessChanging = true; mDirty |= DIRTY_WAKEFULNESS; + + // This is only valid while we are in wakefulness dozing. Set to false otherwise. + mDozeStartInProgress &= (mWakefulness == WAKEFULNESS_DOZING); + if (mNotifier != null) { mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime); } @@ -1631,6 +1640,9 @@ public final class PowerManagerService extends SystemService if (mWakefulness == WAKEFULNESS_DOZING && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) { return; // wait until dream has enabled dozing + } else { + // Doze wakelock acquired (doze started) or device is no longer dozing. + mDozeStartInProgress = false; } if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) { logSleepTimeoutRecapturedLocked(); @@ -2309,6 +2321,10 @@ public final class PowerManagerService extends SystemService isDreaming = false; } + // At this point, we either attempted to start the dream or no attempt will be made, + // so stop holding the display suspend blocker for Doze. + mDozeStartInProgress = false; + // Update dream state. synchronized (mLock) { // Remember the initial battery level when the dream started. @@ -2735,6 +2751,16 @@ public final class PowerManagerService extends SystemService if (mScreenBrightnessBoostInProgress) { return true; } + + // When we transition to DOZING, we have to keep the display suspend blocker + // up until the Doze service has a change to acquire the DOZE wakelock. + // Here we wait for mWakefulnessChanging to become false since the wakefulness + // transition to DOZING isn't considered "changed" until the doze wake lock is + // acquired. + if (mWakefulness == WAKEFULNESS_DOZING && mDozeStartInProgress) { + return true; + } + // Let the system suspend if the screen is off or dozing. return false; } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 5a1eed8897b6..5b697ee89602 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2700,7 +2700,8 @@ class ActivityStarter { || mPreferredDisplayId != DEFAULT_DISPLAY) { final boolean onTop = aOptions == null || !aOptions.getAvoidMoveToFront(); final ActivityStack stack = - mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams); + mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams, + mRequest.realCallingPid, mRequest.realCallingUid); return stack; } // Otherwise handle adjacent launch. @@ -2818,11 +2819,24 @@ class ActivityStarter { return this; } + /** + * Sets the pid of the caller who originally started the activity. + * + * Normally, the pid/uid would be the calling pid from the binder call. + * However, in case of a {@link PendingIntent}, the pid/uid pair of the caller is considered + * the original entity that created the pending intent, in contrast to setRealCallingPid/Uid, + * which represents the entity who invoked pending intent via {@link PendingIntent#send}. + */ ActivityStarter setCallingPid(int pid) { mRequest.callingPid = pid; return this; } + /** + * Sets the uid of the caller who originally started the activity. + * + * @see #setCallingPid + */ ActivityStarter setCallingUid(int uid) { mRequest.callingUid = uid; return this; @@ -2833,11 +2847,25 @@ class ActivityStarter { return this; } + /** + * Sets the pid of the caller who requested to launch the activity. + * + * The pid/uid represents the caller who launches the activity in this request. + * It will almost same as setCallingPid/Uid except when processing {@link PendingIntent}: + * the pid/uid will be the caller who called {@link PendingIntent#send()}. + * + * @see #setCallingPid + */ ActivityStarter setRealCallingPid(int pid) { mRequest.realCallingPid = pid; return this; } + /** + * Sets the uid of the caller who requested to launch the activity. + * + * @see #setRealCallingPid + */ ActivityStarter setRealCallingUid(int uid) { mRequest.realCallingUid = uid; return this; diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index a339ef03c22c..ffbf68813d35 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -1667,7 +1667,8 @@ class RootActivityContainer extends ConfigurationContainer <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) { - return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */); + return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */, + -1 /* no realCallingPid */, -1 /* no realCallingUid */); } /** @@ -1676,13 +1677,16 @@ class RootActivityContainer extends ConfigurationContainer * @param r The activity we are trying to launch. Can be null. * @param options The activity options used to the launch. Can be null. * @param candidateTask The possible task the activity might be launched in. Can be null. - * @params launchParams The resolved launch params to use. + * @param launchParams The resolved launch params to use. + * @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid} + * @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid} * * @return The stack to use for the launch or INVALID_STACK_ID. */ <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop, - @Nullable LaunchParamsController.LaunchParams launchParams) { + @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid, + int realCallingUid) { int taskId = INVALID_TASK_ID; int displayId = INVALID_DISPLAY; //Rect bounds = null; @@ -1713,7 +1717,14 @@ class RootActivityContainer extends ConfigurationContainer if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) { displayId = launchParams.mPreferredDisplayId; } - if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) { + final boolean canLaunchOnDisplayFromStartRequest = + realCallingPid != 0 && realCallingUid > 0 && r != null + && mStackSupervisor.canPlaceEntityOnDisplay(displayId, realCallingPid, + realCallingUid, r.info); + // Checking if the activity's launch caller, or the realCallerId of the activity from + // start request (i.e. PendingIntent caller) is allowed to launch on the display. + if (displayId != INVALID_DISPLAY && (canLaunchOnDisplay(r, displayId) + || canLaunchOnDisplayFromStartRequest)) { if (r != null) { stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options, launchParams); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 6c91e2f52f0c..dc5edcd81586 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -1017,20 +1017,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testCancelImmediatelyAfterEnqueueNotifiesListeners_ForegroundServiceFlag() - throws Exception { - final StatusBarNotification sbn = generateNotificationRecord(null).sbn; - sbn.getNotification().flags = - Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", - sbn.getId(), sbn.getNotification(), sbn.getUserId()); - mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId()); - waitForIdle(); - verify(mListeners, times(1)).notifyPostedLocked(any(), any()); - verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), any()); - } - - @Test public void testUserInitiatedClearAll_noLeak() throws Exception { final NotificationRecord n = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 3d944671ef25..07d9f803d9fa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -341,7 +341,7 @@ public class ActivityStarterTests extends ActivityTestsBase { doReturn(stack).when(mRootActivityContainer) .getLaunchStack(any(), any(), any(), anyBoolean()); doReturn(stack).when(mRootActivityContainer) - .getLaunchStack(any(), any(), any(), anyBoolean(), any()); + .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt()); } // Set up mock package manager internal and make sure no unmocked methods are called diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 3c0da265f97a..84bdecb86826 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -208,6 +208,8 @@ class ActivityTestsBase { private ActivityStack mStack; private int mActivityFlags; private int mLaunchMode; + private int mLaunchedFromPid; + private int mLaunchedFromUid; ActivityBuilder(ActivityTaskManagerService service) { mService = service; @@ -258,6 +260,16 @@ class ActivityTestsBase { return this; } + ActivityBuilder setLaunchedFromPid(int pid) { + mLaunchedFromPid = pid; + return this; + } + + ActivityBuilder setLaunchedFromUid(int uid) { + mLaunchedFromUid = uid; + return this; + } + ActivityRecord build() { if (mComponent == null) { final int id = sCurrentActivityId++; @@ -285,10 +297,11 @@ class ActivityTestsBase { aInfo.launchMode = mLaunchMode; final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, - 0 /* launchedFromPid */, 0, null, intent, null, - aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, - 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, - mService.mStackSupervisor, null /* options */, null /* sourceRecord */); + mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */, + null, intent, null, aInfo /*aInfo*/, new Configuration(), null /* resultTo */, + null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/, + false /* rootVoiceInteraction */, mService.mStackSupervisor, + null /* options */, null /* sourceRecord */); spyOn(activity); activity.mAppWindowToken = mock(AppWindowToken.class); doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 8d2c3dd80538..baf1b0821982 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.TYPE_VIRTUAL; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -61,6 +62,7 @@ import android.content.res.Resources; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.util.Pair; +import android.view.DisplayInfo; import androidx.test.filters.MediumTest; @@ -817,6 +819,41 @@ public class RootActivityContainerTests extends ActivityTestsBase { } /** + * Test that {@link RootActivityContainer#getLaunchStack} with the real caller id will get the + * expected stack when requesting the activity launch on the secondary display. + */ + @Test + public void testGetLaunchStackWithRealCallerId() { + // Create a non-system owned virtual display. + final DisplayInfo info = new DisplayInfo(); + mSupervisor.mService.mContext.getDisplay().getDisplayInfo(info); + info.type = TYPE_VIRTUAL; + info.ownerUid = 100; + final TestActivityDisplay secondaryDisplay = createNewActivityDisplay(info); + mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP); + + // Create an activity with specify the original launch pid / uid. + final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200) + .setLaunchedFromUid(200).build(); + + // Simulate ActivityStarter to find a launch stack for requesting the activity to launch + // on the secondary display with realCallerId. + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(secondaryDisplay.mDisplayId); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); + doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId, + 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info); + final ActivityStack result = mRootActivityContainer.getLaunchStack(r, options, + null /* task */, true /* onTop */, null, 300 /* test realCallerPid */, + 300 /* test realCallerUid */); + + // Assert that the stack is returned as expected. + assertNotNull(result); + assertEquals("The display ID of the stack should same as secondary display ", + secondaryDisplay.mDisplayId, result.mDisplayId); + } + + /** * Mock {@link RootActivityContainerTests#resolveHomeActivity} for returning consistent activity * info for test cases (the original implementation will resolve from the real package manager). */ diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index 99337565e128..735b9a1dcf2e 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -325,9 +325,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { false /* Don't notify for synchronous calls */); // Initialize power save, call active state monitoring logic. - if (status == STATUS_OK && !mRecognitionRequested) { + if (status == STATUS_OK) { initializeTelephonyAndPowerStateListeners(); - mRecognitionRequested = true; } return status; @@ -481,6 +480,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { if (unloadModel && modelData.isModelLoaded()) { Slog.d(TAG, "Unloading previously loaded stale model."); + if (mModule == null) { + return STATUS_ERROR; + } status = mModule.unloadSoundModel(modelData.getHandle()); MetricsLogger.count(mContext, "sth_unloading_stale_model", 1); if (status != SoundTrigger.STATUS_OK) { @@ -550,6 +552,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } + if (mModule == null) { + return STATUS_ERROR; + } int status = mModule.unloadSoundModel(modelData.getHandle()); if (status != SoundTrigger.STATUS_OK) { Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status); @@ -878,6 +883,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { mContext.unregisterReceiver(mPowerSaveModeListener); mPowerSaveModeListener = null; } + mRecognitionRequested = false; } // Clears state for all models (generic and keyphrase). @@ -924,6 +930,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } private void initializeTelephonyAndPowerStateListeners() { + if (mRecognitionRequested) { + return; + } long token = Binder.clearCallingIdentity(); try { // Get the current call state synchronously for the first recognition. @@ -941,6 +950,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } mIsPowerSaveMode = mPowerManager.getPowerSaveState(ServiceType.SOUND) .batterySaverEnabled; + + mRecognitionRequested = true; } finally { Binder.restoreCallingIdentity(token); } @@ -987,6 +998,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { if (exception != null) { Slog.e(TAG, "forceStopAndUnloadModel", exception); } + if (mModule == null) { + return; + } if (modelData.isModelStarted()) { Slog.d(TAG, "Stopping previously started dangling model " + modelData.getHandle()); if (mModule.stopRecognition(modelData.getHandle()) != STATUS_OK) { @@ -1093,6 +1107,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { // a recognition include: no active phone call or not being in a power save mode. Also, // the native service should be enabled. private boolean isRecognitionAllowed() { + // if mRecognitionRequested is false, call and power state listeners are not registered so + // we read current state directly from services + if (!mRecognitionRequested) { + mCallActive = mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK; + mIsPowerSaveMode = + mPowerManager.getPowerSaveState(ServiceType.SOUND).batterySaverEnabled; + } return !mCallActive && !mServiceDisabled && !mIsPowerSaveMode; } @@ -1116,6 +1137,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return STATUS_OK; } + if (mModule == null) { + return STATUS_ERROR; + } int status = mModule.startRecognition(handle, config); if (status != SoundTrigger.STATUS_OK) { Slog.w(TAG, "startRecognition failed with " + status); @@ -1152,8 +1176,11 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } private int stopRecognitionLocked(ModelData modelData, boolean notify) { - IRecognitionStatusCallback callback = modelData.getCallback(); + if (mModule == null) { + return STATUS_ERROR; + } + IRecognitionStatusCallback callback = modelData.getCallback(); // Stop recognition. int status = STATUS_OK; diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index c6c198668d95..163be515f131 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -578,7 +578,8 @@ public class SubscriptionInfo implements Parcelable { PackageManager packageManager = context.getPackageManager(); PackageInfo packageInfo; try { - packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + packageInfo = packageManager.getPackageInfo(packageName, + PackageManager.GET_SIGNING_CERTIFICATES); } catch (PackageManager.NameNotFoundException e) { Log.d("SubscriptionInfo", "canManageSubscription: Unknown package: " + packageName, e); return false; diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 776b168e6766..126644dd0e93 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2612,7 +2612,8 @@ public class SubscriptionManager { PackageManager packageManager = mContext.getPackageManager(); PackageInfo packageInfo; try { - packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + packageInfo = packageManager.getPackageInfo(packageName, + PackageManager.GET_SIGNING_CERTIFICATES); } catch (PackageManager.NameNotFoundException e) { logd("Unknown package: " + packageName); return false; diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java index 37a4491141a0..cb3c3847f08d 100644 --- a/telephony/java/android/telephony/UiccAccessRule.java +++ b/telephony/java/android/telephony/UiccAccessRule.java @@ -19,6 +19,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.pm.PackageInfo; import android.content.pm.Signature; +import android.content.pm.SigningInfo; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -168,17 +169,28 @@ public final class UiccAccessRule implements Parcelable { * * @param packageInfo package info fetched from * {@link android.content.pm.PackageManager#getPackageInfo}. - * {@link android.content.pm.PackageManager#GET_SIGNATURES} must have been passed in. + * {@link android.content.pm.PackageManager#GET_SIGNING_CERTIFICATES} must have been + * passed in. * @return either {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_HAS_ACCESS} or * {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_NO_ACCESS}. */ public int getCarrierPrivilegeStatus(PackageInfo packageInfo) { - if (packageInfo.signatures == null || packageInfo.signatures.length == 0) { + Signature[] signatures = packageInfo.signatures; + SigningInfo sInfo = packageInfo.signingInfo; + + if (sInfo != null) { + signatures = sInfo.getSigningCertificateHistory(); + if (sInfo.hasMultipleSigners()) { + signatures = sInfo.getApkContentsSigners(); + } + } + + if (signatures == null || signatures.length == 0) { throw new IllegalArgumentException( - "Must use GET_SIGNATURES when looking up package info"); + "Must use GET_SIGNING_CERTIFICATES when looking up package info"); } - for (Signature sig : packageInfo.signatures) { + for (Signature sig : signatures) { int accessStatus = getCarrierPrivilegeStatus(sig, packageInfo.packageName); if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { return accessStatus; |