Merge "Prevents scroll capture from targetting secure windows"
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index c2a2c4c..3c3ba59 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -169,31 +169,6 @@
}
/**
- * Request authentication of a crypto object. This call operates the face recognition hardware
- * and starts capturing images. It terminates when
- * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
- * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
- * which point the object is no longer valid. The operation can be canceled by using the
- * provided cancel object.
- *
- * @param crypto object associated with the call or null if none required.
- * @param cancel an object that can be used to cancel authentication
- * @param callback an object to receive authentication events
- * @param handler an optional handler to handle callback events
- * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
- * by
- * <a href="{@docRoot}training/articles/keystore.html">Android
- * Keystore facility</a>.
- * @throws IllegalStateException if the crypto primitive is not initialized.
- * @hide
- */
- @RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
- @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
- authenticate(crypto, cancel, callback, handler, mContext.getUserId());
- }
-
- /**
* Use the provided handler thread for events.
*/
private void useHandler(Handler handler) {
@@ -224,8 +199,10 @@
* @throws IllegalStateException if the crypto primitive is not initialized.
* @hide
*/
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
- @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId) {
+ @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId,
+ boolean isKeyguardBypassEnabled) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback");
}
@@ -247,7 +224,7 @@
final long operationId = crypto != null ? crypto.getOpId() : 0;
Trace.beginSection("FaceManager#authenticate");
mService.authenticate(mToken, operationId, userId, mServiceReceiver,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), isKeyguardBypassEnabled);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e);
if (callback != null) {
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index b9a49c6..db02a0ef 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -46,7 +46,7 @@
// Authenticate the given sessionId with a face
void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
- String opPackageName);
+ String opPackageName, boolean isKeyguardBypassEnabled);
// Uses the face hardware to detect for the presence of a face, without giving details
// about accept/reject/lockout.
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 1f11d10..1a7ec7f 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -782,7 +782,7 @@
int spanStart = runStart;
int spanLimit;
- if (mSpanned == null) {
+ if (mSpanned == null || runStart == runLimit) {
spanLimit = runLimit;
} else {
int target = after ? offset + 1 : offset;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index ce6101f..e9e2fff 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -408,9 +408,4 @@
export_header_lib_headers: [
"jni_headers",
],
- apex_available: [
- "//apex_available:platform",
- "com.android.media",
- "com.android.media.swcodec",
- ],
}
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 7a8da36..684202b 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -25,3 +25,6 @@
toddke@google.com
tsuji@google.com
yamasani@google.com
+
+# Multiuser
+per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index 3d62af0..7f258eb 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -1,26 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.egg"
- android:versionCode="1"
+ android:versionCode="12"
android:versionName="1.0">
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- used for cat notifications -->
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+
<!-- used to save cat images -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
<!-- controls -->
<uses-permission android:name="android.permission.BIND_CONTROLS" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
-
- <activity android:name=".quares.QuaresActivity"
+ <activity
+ android:name=".quares.QuaresActivity"
+ android:exported="true"
android:icon="@drawable/q_icon"
android:label="@string/q_egg_name"
- android:exported="true"
android:theme="@style/QuaresTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -29,9 +31,9 @@
<activity
android:name=".paint.PaintActivity"
android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
+ android:exported="true"
android:icon="@drawable/p_icon"
android:label="@string/p_egg_name"
- android:exported="true"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -39,13 +41,15 @@
</activity>
<!-- Android N easter egg bits -->
- <activity android:name=".neko.NekoLand"
- android:theme="@android:style/Theme.Material.NoActionBar"
+ <activity
+ android:name=".neko.NekoLand"
android:exported="true"
- android:label="@string/app_name">
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Material.NoActionBar">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
<action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@@ -54,25 +58,24 @@
<service
android:name=".neko.NekoService"
android:enabled="true"
- android:permission="android.permission.BIND_JOB_SERVICE"
- android:exported="true" >
- </service>
-
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
<!-- Used to show over lock screen -->
- <activity android:name=".neko.NekoLockedActivity"
+ <activity
+ android:name=".neko.NekoLockedActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar"
- android:showOnLockScreen="true" />
-
+ android:showOnLockScreen="true"
+ android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar" />
<!-- Used to enable easter egg -->
- <activity android:name=".neko.NekoActivationActivity"
+ <activity
+ android:name=".ComponentActivationActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@android:style/Theme.NoDisplay"
- >
+ android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
- <action android:name="android.intent.action.MAIN"/>
+ <action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.android.internal.category.PLATLOGO" />
</intent-filter>
@@ -81,37 +84,65 @@
<!-- The quick settings tile, disabled by default -->
<service
android:name=".neko.NekoTile"
- android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
- android:icon="@drawable/stat_icon"
android:enabled="false"
android:exported="true"
- android:label="@string/default_tile_name">
+ android:icon="@drawable/stat_icon"
+ android:label="@string/default_tile_name"
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
-
- <service android:name=".neko.NekoControlsService"
- android:permission="android.permission.BIND_CONTROLS"
- android:label="@string/r_egg_name"
- android:icon="@drawable/ic_fullcat_icon"
+ <service
+ android:name=".neko.NekoControlsService"
android:enabled="false"
- android:exported="true">
+ android:exported="true"
+ android:icon="@drawable/ic_fullcat_icon"
+ android:label="@string/r_egg_name"
+ android:permission="android.permission.BIND_CONTROLS">
<intent-filter>
<action android:name="android.service.controls.ControlsProviderService" />
</intent-filter>
- </service>
-
- <!-- FileProvider for sending pictures -->
+ </service> <!-- FileProvider for sending pictures -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.android.egg.fileprovider"
- android:grantUriPermissions="true"
- android:exported="false">
+ android:exported="false"
+ android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
+
+ <!-- Android S easter egg bits -->
+
+ <!-- List of all system theme colors on the device. -->
+ <activity
+ android:name=".widget.PaintChipsActivity"
+ android:theme="@android:style/Theme.Material.Wallpaper.NoTitleBar"
+ android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
+ android:label="@string/s_egg_name"
+ android:enabled="false"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
+ <!-- Homescreen widget also showing paint chips (may be affected by the exact position in
+ the workspace) -->
+ <receiver
+ android:name=".widget.PaintChipsWidget"
+ android:label="@string/s_egg_name"
+ android:enabled="false">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.appwidget.provider"
+ android:resource="@xml/paint_chips_widget_info" />
+ </receiver>
</application>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/packages/EasterEgg/build.gradle b/packages/EasterEgg/build.gradle
index 20b4698..0565369 100644
--- a/packages/EasterEgg/build.gradle
+++ b/packages/EasterEgg/build.gradle
@@ -7,8 +7,8 @@
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.0.0'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.android.tools.build:gradle:7.0.0-alpha08'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.30"
}
}
@@ -62,6 +62,9 @@
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ buildFeatures {
+ viewBinding true
+ }
}
@@ -74,6 +77,7 @@
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6'
implementation "androidx.recyclerview:recyclerview:${ANDROID_X_VERSION}"
implementation "androidx.dynamicanimation:dynamicanimation:${ANDROID_X_VERSION}"
+ implementation 'com.google.android.material:material:1.3.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
diff --git a/packages/EasterEgg/gradle.properties b/packages/EasterEgg/gradle.properties
index e8e6450..0b5a736 100644
--- a/packages/EasterEgg/gradle.properties
+++ b/packages/EasterEgg/gradle.properties
@@ -19,5 +19,5 @@
kotlin.code.style=official
ANDROID_X_VERSION=1+
-COMPILE_SDK=android-30
+COMPILE_SDK=android-S
BUILD_TOOLS_VERSION=28.0.3
diff --git a/packages/EasterEgg/res/drawable/android_s.xml b/packages/EasterEgg/res/drawable/android_s.xml
new file mode 100644
index 0000000..9cecab1
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android_s.xml
@@ -0,0 +1,23 @@
+<vector android:height="108dp" android:viewportHeight="48"
+ android:viewportWidth="48" android:width="108dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <group>
+ <clip-path android:pathData="M17,14h14v20h-14z"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M18,21C18,21.7956 18.3161,22.5587 18.8787,23.1213C19.4413,23.6839 20.2044,24 21,24H27C27.7956,24 28.5587,24.3161 29.1213,24.8787C29.6839,25.4413 30,26.2044 30,27"
+ android:strokeColor="#ffffff" android:strokeWidth="2"/>
+ <path android:fillColor="#ffffff" android:pathData="M22,21C22.5523,21 23,20.5523 23,20C23,19.4477 22.5523,19 22,19C21.4477,19 21,19.4477 21,20C21,20.5523 21.4477,21 22,21Z"/>
+ <path android:fillColor="#ffffff" android:pathData="M26,21C26.5523,21 27,20.5523 27,20C27,19.4477 26.5523,19 26,19C25.4477,19 25,19.4477 25,20C25,20.5523 25.4477,21 26,21Z"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M19.5,16.5L18,15"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M28.5,16.5L30,15"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M29.92,20C29.8637,19.6605 29.7801,19.3261 29.67,19C29.205,17.6561 28.2777,16.5211 27.0536,15.7973C25.8294,15.0735 24.388,14.8081 22.9864,15.0483C21.5847,15.2885 20.314,16.0188 19.4007,17.1088C18.4874,18.1989 17.991,19.5779 18,21"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ <path android:fillColor="#00000000"
+ android:pathData="M18.08,28C18.1363,28.3395 18.2199,28.6739 18.33,29C18.795,30.3439 19.7223,31.4789 20.9464,32.2027C22.1705,32.9265 23.612,33.1919 25.0136,32.9517C26.4153,32.7115 27.686,31.9812 28.5993,30.8912C29.5126,29.8011 30.009,28.4221 30,27"
+ android:strokeColor="#ffffff" android:strokeLineCap="round" android:strokeWidth="2"/>
+ </group>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml
index 7f8d4fa..7054962 100644
--- a/packages/EasterEgg/res/drawable/icon.xml
+++ b/packages/EasterEgg/res/drawable/icon.xml
@@ -15,5 +15,5 @@
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/android_11_dial"/>
+ <foreground android:drawable="@drawable/android_s"/>
</adaptive-icon>
diff --git a/packages/EasterEgg/res/drawable/icon_bg.xml b/packages/EasterEgg/res/drawable/icon_bg.xml
index 31b2a7f..d08e160 100644
--- a/packages/EasterEgg/res/drawable/icon_bg.xml
+++ b/packages/EasterEgg/res/drawable/icon_bg.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#073042" />
+ android:color="@android:color/system_accent2_500" />
diff --git a/packages/EasterEgg/res/drawable/roundrect.xml b/packages/EasterEgg/res/drawable/roundrect.xml
new file mode 100644
index 0000000..070adad
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/roundrect.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#FF000000" />
+ <corners
+ android:radius="12dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/paint_chip.xml b/packages/EasterEgg/res/layout/paint_chip.xml
new file mode 100644
index 0000000..d5745b9
--- /dev/null
+++ b/packages/EasterEgg/res/layout/paint_chip.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/chip"
+ android:layout_width="10dp" android:layout_height="10dp"
+ android:layout_gravity="fill" android:layout_columnWeight="1" android:layout_rowWeight="1"
+ android:text="A1-500"
+ android:backgroundTint="@android:color/system_accent1_500"
+ android:background="@drawable/roundrect"
+ android:gravity="center"
+ android:textColor="?android:attr/textColorPrimary"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:layout_margin="2dp"
+ android:singleLine="true"
+ />
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/paint_chips_grid.xml b/packages/EasterEgg/res/layout/paint_chips_grid.xml
new file mode 100644
index 0000000..79f7013
--- /dev/null
+++ b/packages/EasterEgg/res/layout/paint_chips_grid.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2021 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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/paint_grid"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="0dp"
+ android:orientation="vertical"
+ android:alignmentMode="alignBounds"
+ android:rowOrderPreserved="false"
+ >
+</GridLayout>
diff --git a/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml b/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml
new file mode 100644
index 0000000..9893ec0
--- /dev/null
+++ b/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml
@@ -0,0 +1,79 @@
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="300dp"
+ android:layout_height="50dp"
+ android:alignmentMode="alignBounds"
+ android:columnCount="5"
+ android:padding="0dp"
+ android:rowCount="1"
+ android:rowOrderPreserved="false">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_neutral1_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="N1-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_neutral2_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="N2-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_accent1_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="A1-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_accent2_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="A2-500"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowWeight="1"
+ android:layout_columnWeight="1"
+ android:layout_gravity="fill"
+ android:layout_margin="2dp"
+ android:background="@drawable/roundrect"
+ android:backgroundTint="@android:color/system_accent3_500"
+ android:fontFamily="?android:attr/textAppearanceLarge"
+ android:gravity="center"
+ android:text="A3-500"
+ android:textColor="?android:attr/textColorPrimary" />
+</GridLayout>
diff --git a/packages/EasterEgg/res/values-night/themes.xml b/packages/EasterEgg/res/values-night/themes.xml
new file mode 100644
index 0000000..83ec7a5
--- /dev/null
+++ b/packages/EasterEgg/res/values-night/themes.xml
@@ -0,0 +1,7 @@
+<resources>
+
+ <style name="ThemeOverlay.EasterEgg.AppWidgetContainer" parent="">
+ <item name="appWidgetBackgroundColor">@color/light_blue_900</item>
+ <item name="appWidgetTextColor">@color/light_blue_200</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/attrs.xml b/packages/EasterEgg/res/values/attrs.xml
new file mode 100644
index 0000000..97531a2
--- /dev/null
+++ b/packages/EasterEgg/res/values/attrs.xml
@@ -0,0 +1,6 @@
+<resources>
+ <declare-styleable name="AppWidgetAttrs">
+ <attr name="appWidgetBackgroundColor" format="color" />
+ <attr name="appWidgetTextColor" format="color" />
+ </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/colors.xml b/packages/EasterEgg/res/values/colors.xml
index 1a5388b..d79e83b 100644
--- a/packages/EasterEgg/res/values/colors.xml
+++ b/packages/EasterEgg/res/values/colors.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,4 +17,8 @@
<color name="toolbar_bg_color">#FFDDDDDD</color>
<color name="paper_color">#FFFFFFFF</color>
<color name="paint_color">#FF000000</color>
+ <color name="light_blue_50">#FFE1F5FE</color>
+ <color name="light_blue_200">#FF81D4FA</color>
+ <color name="light_blue_600">#FF039BE5</color>
+ <color name="light_blue_900">#FF01579B</color>
</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/values/dimens.xml
index e9dcebd..0de2c3c 100644
--- a/packages/EasterEgg/res/values/dimens.xml
+++ b/packages/EasterEgg/res/values/dimens.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,4 +15,10 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<dimen name="neko_display_size">64dp</dimen>
+
+ <!--
+Refer to App Widget Documentation for margin information
+http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
+ -->
+ <dimen name="widget_margin">0dp</dimen>
</resources>
diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml
index 25f9421..743947a 100644
--- a/packages/EasterEgg/res/values/strings.xml
+++ b/packages/EasterEgg/res/values/strings.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <string name="app_name" translatable="false">Android R Easter Egg</string>
+ <string name="app_name" translatable="false">Android S Easter Egg</string>
<!-- name of the Q easter egg, a nonogram-style icon puzzle -->
<string name="q_egg_name" translatable="false">Icon Quiz</string>
@@ -23,4 +23,8 @@
<string name="p_egg_name" translatable="false">PAINT.APK</string>
<string name="r_egg_name" translatable="false">Cat Controls</string>
+
+ <!-- name of the S easter egg, a widget that displays the system color palette
+ in a manner similar to a set of paint samples from a hardware store -->
+ <string name="s_egg_name" translatable="false">Paint Chips</string>
</resources>
diff --git a/packages/EasterEgg/res/values/themes.xml b/packages/EasterEgg/res/values/themes.xml
new file mode 100644
index 0000000..5b16304
--- /dev/null
+++ b/packages/EasterEgg/res/values/themes.xml
@@ -0,0 +1,7 @@
+<resources>
+
+ <style name="ThemeOverlay.EasterEgg.AppWidgetContainer" parent="">
+ <item name="appWidgetBackgroundColor">@color/light_blue_600</item>
+ <item name="appWidgetTextColor">@color/light_blue_50</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/xml/paint_chips_widget_info.xml b/packages/EasterEgg/res/xml/paint_chips_widget_info.xml
new file mode 100644
index 0000000..7780a75
--- /dev/null
+++ b/packages/EasterEgg/res/xml/paint_chips_widget_info.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:initialLayout="@layout/paint_chip"
+ android:previewLayout="@layout/paint_chips_widget_preview"
+ android:minWidth="50dp"
+ android:minHeight="50dp"
+ android:resizeMode="horizontal|vertical"
+ android:updatePeriodMillis="86400000"
+ android:widgetCategory="home_screen"></appwidget-provider>
\ No newline at end of file
diff --git a/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java
new file mode 100644
index 0000000..5820b5a
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 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.egg;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.egg.neko.NekoControlsService;
+import com.android.egg.widget.PaintChipsActivity;
+import com.android.egg.widget.PaintChipsWidget;
+
+/**
+ * Launched from the PlatLogoActivity. Enables everything else in this easter egg.
+ */
+public class ComponentActivationActivity extends Activity {
+ private static final String TAG = "EasterEgg";
+
+ private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s";
+
+ private void toastUp(String s) {
+ Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
+ toast.show();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ final PackageManager pm = getPackageManager();
+ final ComponentName[] cns = new ComponentName[] {
+ new ComponentName(this, NekoControlsService.class),
+ new ComponentName(this, PaintChipsActivity.class),
+ new ComponentName(this, PaintChipsWidget.class)
+ };
+ final long unlockValue = Settings.System.getLong(getContentResolver(),
+ S_EGG_UNLOCK_SETTING, 0);
+ for (ComponentName cn : cns) {
+ final boolean componentEnabled = pm.getComponentEnabledSetting(cn)
+ == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ if (unlockValue == 0) {
+ if (componentEnabled) {
+ Log.v(TAG, "Disabling component: " + cn);
+ pm.setComponentEnabledSetting(cn,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ //toastUp("\uD83D\uDEAB");
+ } else {
+ Log.v(TAG, "Already disabled: " + cn);
+ }
+ } else {
+ if (!componentEnabled) {
+ Log.v(TAG, "Enabling component: " + cn);
+ pm.setComponentEnabledSetting(cn,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
+ //toastUp("\uD83D\uDC31");
+ } else {
+ Log.v(TAG, "Already enabled: " + cn);
+ }
+ }
+ }
+
+ finish();
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
deleted file mode 100644
index df461c6..0000000
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 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.egg.neko;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.pm.PackageManager;
-import android.provider.Settings;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-
-public class NekoActivationActivity extends Activity {
- private static final String R_EGG_UNLOCK_SETTING = "egg_mode_r";
-
- private void toastUp(String s) {
- Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
- toast.show();
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- final PackageManager pm = getPackageManager();
- final ComponentName cn = new ComponentName(this, NekoControlsService.class);
- final boolean componentEnabled = pm.getComponentEnabledSetting(cn)
- == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
- if (Settings.System.getLong(getContentResolver(),
- R_EGG_UNLOCK_SETTING, 0) == 0) {
- if (componentEnabled) {
- Log.v("Neko", "Disabling controls.");
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- MetricsLogger.histogram(this, "egg_neko_enable", 0);
- toastUp("\uD83D\uDEAB");
- } else {
- Log.v("Neko", "Controls already disabled.");
- }
- } else {
- if (!componentEnabled) {
- Log.v("Neko", "Enabling controls.");
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP);
- MetricsLogger.histogram(this, "egg_neko_enable", 1);
- toastUp("\uD83D\uDC31");
- } else {
- Log.v("Neko", "Controls already enabled.");
- }
- }
- finish();
- }
-}
diff --git a/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt
new file mode 100644
index 0000000..8799aec
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 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.egg.widget
+
+import android.app.Activity
+import android.content.res.Configuration
+import android.os.Bundle
+import android.widget.FrameLayout
+
+/**
+ * Activity to show off the current dynamic system theme in all its glory.
+ */
+class PaintChipsActivity : Activity() {
+ private lateinit var layout: FrameLayout
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ window.navigationBarColor = 0
+ window.statusBarColor = 0
+ actionBar?.hide()
+
+ layout = FrameLayout(this)
+ layout.setPadding(dp2px(8f), dp2px(8f), dp2px(8f), dp2px(8f))
+ rebuildGrid()
+
+ setContentView(layout)
+ }
+
+ fun dp2px(dp: Float): Int {
+ return (dp * resources.displayMetrics.density).toInt()
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ rebuildGrid()
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+
+ rebuildGrid()
+ }
+
+ private fun rebuildGrid() {
+ layout.removeAllViews()
+ val grid = buildFullWidget(this, ClickBehavior.SHARE)
+ val asView = grid.apply(this, layout)
+ layout.addView(asView, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT))
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt
new file mode 100644
index 0000000..c15cabb
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2021 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.egg.widget
+
+import android.app.PendingIntent
+import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProvider
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.util.SizeF
+import android.widget.RemoteViews
+
+import com.android.egg.R
+
+/**
+ * A homescreen widget to explore the current dynamic system theme.
+ */
+class PaintChipsWidget : AppWidgetProvider() {
+ override fun onUpdate(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetIds: IntArray
+ ) {
+ for (appWidgetId in appWidgetIds) {
+ updateAppWidget(context, appWidgetManager, appWidgetId)
+ }
+ }
+
+ override fun onAppWidgetOptionsChanged(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int,
+ newOptions: Bundle?
+ ) {
+ // Log.v(TAG, "onAppWidgetOptionsChanged: id=${appWidgetId}")
+ updateAppWidget(context, appWidgetManager, appWidgetId)
+ super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
+ }
+}
+
+const val TAG = "PaintChips"
+
+val SHADE_NUMBERS = intArrayOf(0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
+
+val COLORS_NEUTRAL1 = intArrayOf(
+ android.R.color.system_neutral1_0,
+ android.R.color.system_neutral1_10,
+ android.R.color.system_neutral1_50,
+ android.R.color.system_neutral1_100,
+ android.R.color.system_neutral1_200,
+ android.R.color.system_neutral1_300,
+ android.R.color.system_neutral1_400,
+ android.R.color.system_neutral1_500,
+ android.R.color.system_neutral1_600,
+ android.R.color.system_neutral1_700,
+ android.R.color.system_neutral1_800,
+ android.R.color.system_neutral1_900,
+ android.R.color.system_neutral1_1000
+)
+
+val COLORS_NEUTRAL2 = intArrayOf(
+ android.R.color.system_neutral2_0,
+ android.R.color.system_neutral2_10,
+ android.R.color.system_neutral2_50,
+ android.R.color.system_neutral2_100,
+ android.R.color.system_neutral2_200,
+ android.R.color.system_neutral2_300,
+ android.R.color.system_neutral2_400,
+ android.R.color.system_neutral2_500,
+ android.R.color.system_neutral2_600,
+ android.R.color.system_neutral2_700,
+ android.R.color.system_neutral2_800,
+ android.R.color.system_neutral2_900,
+ android.R.color.system_neutral2_1000
+)
+
+var COLORS_ACCENT1 = intArrayOf(
+ android.R.color.system_accent1_0,
+ android.R.color.system_accent1_10,
+ android.R.color.system_accent1_50,
+ android.R.color.system_accent1_100,
+ android.R.color.system_accent1_200,
+ android.R.color.system_accent1_300,
+ android.R.color.system_accent1_400,
+ android.R.color.system_accent1_500,
+ android.R.color.system_accent1_600,
+ android.R.color.system_accent1_700,
+ android.R.color.system_accent1_800,
+ android.R.color.system_accent1_900,
+ android.R.color.system_accent1_1000
+)
+
+var COLORS_ACCENT2 = intArrayOf(
+ android.R.color.system_accent2_0,
+ android.R.color.system_accent2_10,
+ android.R.color.system_accent2_50,
+ android.R.color.system_accent2_100,
+ android.R.color.system_accent2_200,
+ android.R.color.system_accent2_300,
+ android.R.color.system_accent2_400,
+ android.R.color.system_accent2_500,
+ android.R.color.system_accent2_600,
+ android.R.color.system_accent2_700,
+ android.R.color.system_accent2_800,
+ android.R.color.system_accent2_900,
+ android.R.color.system_accent2_1000
+)
+
+var COLORS_ACCENT3 = intArrayOf(
+ android.R.color.system_accent3_0,
+ android.R.color.system_accent3_10,
+ android.R.color.system_accent3_50,
+ android.R.color.system_accent3_100,
+ android.R.color.system_accent3_200,
+ android.R.color.system_accent3_300,
+ android.R.color.system_accent3_400,
+ android.R.color.system_accent3_500,
+ android.R.color.system_accent3_600,
+ android.R.color.system_accent3_700,
+ android.R.color.system_accent3_800,
+ android.R.color.system_accent3_900,
+ android.R.color.system_accent3_1000
+)
+
+var COLOR_NAMES = arrayOf(
+ "N1", "N2", "A1", "A2", "A3"
+)
+
+var COLORS = arrayOf(
+ COLORS_NEUTRAL1,
+ COLORS_NEUTRAL2,
+ COLORS_ACCENT1,
+ COLORS_ACCENT2,
+ COLORS_ACCENT3
+)
+
+internal fun updateAppWidget(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int
+) {
+ // val opts = appWidgetManager.getAppWidgetOptions(appWidgetId)
+ // Log.v(TAG, "requested sizes=${opts[OPTION_APPWIDGET_SIZES]}")
+
+ val allSizes = mapOf(
+ SizeF(50f, 50f)
+ to buildWidget(context, 1, 1, ClickBehavior.LAUNCH),
+ SizeF(100f, 50f)
+ to buildWidget(context, 1, 2, ClickBehavior.LAUNCH),
+ SizeF(150f, 50f)
+ to buildWidget(context, 1, 3, ClickBehavior.LAUNCH),
+ SizeF(200f, 50f)
+ to buildWidget(context, 1, 4, ClickBehavior.LAUNCH),
+ SizeF(250f, 50f)
+ to buildWidget(context, 1, 5, ClickBehavior.LAUNCH),
+
+ SizeF(50f, 120f)
+ to buildWidget(context, 3, 1, ClickBehavior.LAUNCH),
+ SizeF(100f, 120f)
+ to buildWidget(context, 3, 2, ClickBehavior.LAUNCH),
+ SizeF(150f, 120f)
+ to buildWidget(context, 3, 3, ClickBehavior.LAUNCH),
+ SizeF(200f, 120f)
+ to buildWidget(context, 3, 4, ClickBehavior.LAUNCH),
+ SizeF(250f, 120f)
+ to buildWidget(context, 3, 5, ClickBehavior.LAUNCH),
+
+ SizeF(50f, 250f)
+ to buildWidget(context, 5, 1, ClickBehavior.LAUNCH),
+ SizeF(100f, 250f)
+ to buildWidget(context, 5, 2, ClickBehavior.LAUNCH),
+ SizeF(150f, 250f)
+ to buildWidget(context, 5, 3, ClickBehavior.LAUNCH),
+ SizeF(200f, 250f)
+ to buildWidget(context, 5, 4, ClickBehavior.LAUNCH),
+ SizeF(250f, 250f)
+ to buildWidget(context, 5, 5, ClickBehavior.LAUNCH),
+
+ SizeF(300f, 300f)
+ to buildWidget(context, SHADE_NUMBERS.size, COLORS.size, ClickBehavior.LAUNCH)
+ )
+
+ // Instruct the widget manager to update the widget
+ appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(allSizes))
+}
+
+fun buildFullWidget(context: Context, clickable: ClickBehavior): RemoteViews {
+ return buildWidget(context, SHADE_NUMBERS.size, COLORS.size, clickable)
+}
+
+fun buildWidget(context: Context, numShades: Int, numColors: Int, clickable: ClickBehavior):
+ RemoteViews {
+ val grid = RemoteViews(context.packageName, R.layout.paint_chips_grid)
+
+ // shouldn't be necessary but sometimes the RV instructions get played twice in launcher.
+ grid.removeAllViews(R.id.paint_grid)
+
+ grid.setInt(R.id.paint_grid, "setRowCount", numShades)
+ grid.setInt(R.id.paint_grid, "setColumnCount", numColors)
+
+ Log.v(TAG, "building widget: shade rows=$numShades, color columns=$numColors")
+
+ COLORS.forEachIndexed colorLoop@{ i, colorlist ->
+ when (colorlist) {
+ COLORS_NEUTRAL1 -> if (numColors < 2) return@colorLoop
+ COLORS_NEUTRAL2 -> if (numColors < 4) return@colorLoop
+ COLORS_ACCENT2 -> if (numColors < 3) return@colorLoop
+ COLORS_ACCENT3 -> if (numColors < 5) return@colorLoop
+ else -> {} // always do ACCENT1
+ }
+ colorlist.forEachIndexed shadeLoop@{ j, resId ->
+ when (SHADE_NUMBERS[j]) {
+ 500 -> {}
+ 300, 700 -> if (numShades < 3) return@shadeLoop
+ 100, 900 -> if (numShades < 5) return@shadeLoop
+ else -> if (numShades < SHADE_NUMBERS.size) return@shadeLoop
+ }
+ val cell = RemoteViews(context.packageName, R.layout.paint_chip)
+ cell.setTextViewText(R.id.chip, "${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]}")
+ val textColor = if (SHADE_NUMBERS[j] > 500)
+ colorlist[0]
+ else colorlist[colorlist.size - 1]
+ cell.setTextColor(R.id.chip, context.getColor(textColor))
+ cell.setColorStateList(R.id.chip, "setBackgroundTintList", resId)
+ val text = """
+ ${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]} (@${
+ context.resources.getResourceName(resId) })
+ currently: #${ String.format("%06x", context.getColor(resId) and 0xFFFFFF) }
+ """.trimIndent()
+ when (clickable) {
+ ClickBehavior.SHARE -> cell.setOnClickPendingIntent(
+ R.id.chip,
+ makeTextSharePendingIntent(context, text)
+ )
+ ClickBehavior.LAUNCH -> cell.setOnClickPendingIntent(
+ R.id.chip,
+ makeActivityLaunchPendingIntent(context)
+ )
+ ClickBehavior.NONE -> { }
+ }
+ grid.addView(R.id.paint_grid, cell)
+ }
+ }
+
+ return grid
+}
+
+enum class ClickBehavior {
+ NONE,
+ SHARE,
+ LAUNCH
+}
+
+fun makeTextSharePendingIntent(context: Context, text: String): PendingIntent {
+ val shareIntent: Intent = Intent().apply {
+ action = Intent.ACTION_SEND
+ putExtra(Intent.EXTRA_TEXT, text)
+ type = "text/plain"
+ }
+
+ val chooserIntent = Intent.createChooser(shareIntent, null).apply {
+ identifier = text // incredible quality-of-life improvement, thanks framework team
+ }
+
+ return PendingIntent.getActivity(context, 0, chooserIntent,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
+}
+
+fun makeActivityLaunchPendingIntent(context: Context): PendingIntent {
+ return PendingIntent.getActivity(context, 0,
+ Intent().apply {
+ component = ComponentName(context, PaintChipsActivity::class.java)
+ action = Intent.ACTION_MAIN
+ },
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
+}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 6b840bd..183a06c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -20,67 +20,67 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Toast message when Wi-Fi cannot scan for networks -->
<string name="wifi_fail_to_scan">Can\'t scan for networks</string>
- <!-- Do not translate. Concise terminology for wifi with WEP security -->
+ <!-- Concise terminology for wifi with WEP security -->
<string name="wifi_security_short_wep" translatable="false">WEP</string>
- <!-- Do not translate. Concise terminology for wifi with WPA security -->
+ <!-- Concise terminology for wifi with WPA security -->
<string name="wifi_security_short_wpa" translatable="false">WPA</string>
- <!-- Do not translate. Concise terminology for wifi with WPA2 security -->
+ <!-- Concise terminology for wifi with WPA2 security -->
<string name="wifi_security_short_wpa2" translatable="false">WPA2</string>
- <!-- Do not translate. Concise terminology for wifi with both WPA/WPA2 security -->
+ <!-- Concise terminology for wifi with both WPA/WPA2 security -->
<string name="wifi_security_short_wpa_wpa2" translatable="false">WPA/WPA2</string>
- <!-- Do not translate. Concise terminology for wifi with unknown PSK type -->
+ <!-- Concise terminology for wifi with unknown PSK type -->
<string name="wifi_security_short_psk_generic" translatable="false">@string/wifi_security_short_wpa_wpa2</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
+ <!-- Concise terminology for wifi with 802.1x EAP security -->
<string name="wifi_security_short_eap" translatable="false">802.1x</string>
- <!-- Do not translate. Concise terminology for wifi with WPA 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA 802.1x EAP security -->
<string name="wifi_security_short_eap_wpa" translatable="false">WPA-EAP</string>
- <!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
<string name="wifi_security_short_eap_wpa2_wpa3" translatable="false">RSN-EAP</string>
- <!-- Do not translate. Concise terminology for wifi with WPA3 security -->
+ <!-- Concise terminology for wifi with WPA3 security -->
<string name="wifi_security_short_sae" translatable="false">WPA3</string>
- <!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 transition security -->
+ <!-- Concise terminology for wifi with WPA2/WPA3 transition security -->
<string name="wifi_security_short_psk_sae" translatable="false">WPA2/WPA3</string>
- <!-- Do not translate. Concise terminology for Wi-Fi with None/OWE transition mode security -->
+ <!-- Concise terminology for Wi-Fi with None/OWE transition mode security -->
<string name="wifi_security_short_none_owe" translatable="false">None/OWE</string>
- <!-- Do not translate. Concise terminology for wifi with OWE security -->
+ <!-- Concise terminology for wifi with OWE security -->
<string name="wifi_security_short_owe" translatable="false">OWE</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
+ <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
<string name="wifi_security_short_eap_suiteb" translatable="false">Suite-B-192</string>
<!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. [CHAR LIMIT=40] -->
<string name="wifi_security_none">None</string>
- <!-- Do not translate. Terminology for wifi with WEP security -->
+ <!-- Terminology for wifi with WEP security -->
<string name="wifi_security_wep" translatable="false">WEP</string>
- <!-- Do not translate. Terminology for wifi with WPA security -->
+ <!-- Terminology for wifi with WPA security -->
<string name="wifi_security_wpa" translatable="false">WPA-Personal</string>
- <!-- Do not translate. Terminology for wifi with WPA2 security -->
+ <!-- Terminology for wifi with WPA2 security -->
<string name="wifi_security_wpa2" translatable="false">WPA2-Personal</string>
- <!-- Do not translate. Terminology for wifi with both WPA/WPA2 security, or unknown -->
+ <!-- Terminology for wifi with both WPA/WPA2 security, or unknown -->
<string name="wifi_security_wpa_wpa2" translatable="false">WPA/WPA2-Personal</string>
- <!-- Do not translate. Terminology for wifi with unknown PSK type -->
+ <!-- Terminology for wifi with unknown PSK type -->
<string name="wifi_security_psk_generic" translatable="false">@string/wifi_security_wpa_wpa2</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
+ <!-- Concise terminology for wifi with 802.1x EAP security -->
<string name="wifi_security_eap" translatable="false">WPA/WPA2/WPA3-Enterprise</string>
- <!-- Do not translate. Concise terminology for wifi with WPA 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA 802.1x EAP security -->
<string name="wifi_security_eap_wpa" translatable="false">WPA-Enterprise</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
+ <!-- Concise terminology for wifi with 802.1x EAP security -->
<string name="wifi_security_eap_wpa_wpa2" translatable="false">WPA/WPA2-Enterprise</string>
- <!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
<string name="wifi_security_eap_wpa2_wpa3" translatable="false">WPA2/WPA3-Enterprise</string>
- <!-- Do not translate. Concise terminology for wifi with WPA3 802.1x EAP security -->
+ <!-- Concise terminology for wifi with WPA3 802.1x EAP security -->
<string name="wifi_security_eap_wpa3" translatable="false">WPA3-Enterprise</string>
- <!-- Do not translate. Concise terminology for Passpoint network -->
+ <!-- Concise terminology for Passpoint network -->
<string name="wifi_security_passpoint" translatable="false">Passpoint</string>
- <!-- Do not translate. Terminology for wifi with WPA3 security -->
+ <!-- Terminology for wifi with WPA3 security -->
<string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
- <!-- Do not translate. Terminology for wifi with WPA2/WPA3 Transition mode security -->
+ <!-- Terminology for wifi with WPA2/WPA3 Transition mode security -->
<string name="wifi_security_psk_sae" translatable="false">WPA2/WPA3-Personal</string>
- <!-- Do not translate. Terminology for Wi-Fi with None/OWE transition mode security -->
+ <!-- Terminology for Wi-Fi with None/OWE transition mode security -->
<string name="wifi_security_none_owe" translatable="false">None/Enhanced Open</string>
- <!-- Do not translate. Terminology for wifi with OWE security -->
+ <!-- Terminology for wifi with OWE security -->
<string name="wifi_security_owe" translatable="false">Enhanced Open</string>
- <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
+ <!-- Concise terminology for wifi with 802.1x EAP Suite-B-192 security -->
<string name="wifi_security_eap_suiteb" translatable="false">WPA3-Enterprise 192-bit</string>
<!-- Summary for the remembered network. -->
@@ -654,7 +654,7 @@
<!-- Setting Checkbox title whether to disable WiFi Scan Throttling. [CHAR LIMIT=40] -->
<string name="wifi_scan_throttling">Wi\u2011Fi scan throttling</string>
<!-- Setting Checkbox title whether to enable WiFi non-persistent mac randomization. [CHAR LIMIT=80] -->
- <string name="wifi_enhanced_mac_randomization">Wi\u2011Fi non\u2011persistent MAC randomization</string>
+ <string name="wifi_non_persistent_mac_randomization">Wi\u2011Fi non\u2011persistent MAC randomization</string>
<!-- Setting Checkbox title whether to always keep mobile data active. [CHAR LIMIT=80] -->
<string name="mobile_data_always_on">Mobile data always active</string>
<!-- Setting Checkbox title whether to enable hardware acceleration for tethering. [CHAR LIMIT=80] -->
@@ -722,8 +722,8 @@
<string name="wifi_verbose_logging_summary">Increase Wi\u2011Fi logging level, show per SSID RSSI in Wi\u2011Fi Picker</string>
<!-- Setting Checkbox summary whether to disable Wifi scan throttling [CHAR LIMIT=NONE] -->
<string name="wifi_scan_throttling_summary">Reduces battery drain & improves network performance</string>
- <!-- Setting Checkbox title whether to enable WiFi enhanced mac randomization. [CHAR LIMIT=NONE] -->
- <string name="wifi_enhanced_mac_randomization_summary">When this mode is enabled, this device\u2019s MAC address may change each time it connects to a network that has MAC randomization enabled.</string>
+ <!-- Setting Checkbox summary whether to enable WiFi non-persistent mac randomization. [CHAR LIMIT=NONE] -->
+ <string name="wifi_non_persistent_mac_randomization_summary">When this mode is enabled, this device\u2019s MAC address may change each time it connects to a network that has MAC randomization enabled.</string>
<!-- Label indicating network has been manually marked as metered -->
<string name="wifi_metered_label">Metered</string>
<!-- Label indicating network has been manually marked as unmetered -->
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index b84a9cd..0ad8f39d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -79,5 +79,7 @@
Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED,
Settings.Global.DEVICE_CONFIG_SYNC_DISABLED,
Settings.Global.POWER_BUTTON_LONG_PRESS,
+ Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
+ Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index a9245f8..f0c2e0d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -143,6 +143,8 @@
/* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.DEVICE_CONFIG_SYNC_DISABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.AUTOMATIC_POWER_SAVE_MODE, ANY_INTEGER_VALIDATOR);
+ VALIDATORS.put(Global.ADVANCED_BATTERY_USAGE_AMOUNT, PERCENTAGE_INTEGER_VALIDATOR);
VALIDATORS.put(Global.Wearable.HAS_PAY_TOKENS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN, ANY_INTEGER_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 6a4b5e9..9e3691f 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -138,7 +138,6 @@
Settings.Global.AUTOFILL_LOGGING_LEVEL,
Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
- Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
@@ -593,7 +592,6 @@
Settings.Global.CACHED_APPS_FREEZER_ENABLED,
Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
- Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT,
Settings.Global.Wearable.HAS_PAY_TOKENS,
Settings.Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN,
Settings.Global.Wearable.HOTWORD_DETECTION_ENABLED,
diff --git a/packages/SystemUI/res/drawable-nodpi/android_12.xml b/packages/SystemUI/res/drawable-nodpi/android_12.xml
new file mode 100644
index 0000000..bdeeced
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/android_12.xml
@@ -0,0 +1,37 @@
+<!--
+Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+ <group>
+ <clip-path
+ android:pathData="M14,14h21v20h-21z"/>
+ <path
+ android:pathData="M15,15C15.7956,15 16.5587,15.3161 17.1213,15.8787C17.6839,16.4413 18,17.2044 18,18V33"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M34,33H22V30C22,28.4087 22.6321,26.8826 23.7574,25.7574C24.8826,24.6321 26.4087,24 28,24H31C31.7956,24 32.5587,23.6839 33.1213,23.1213C33.6839,22.5587 34,21.7957 34,21C34.009,19.5779 33.5126,18.1989 32.5993,17.1088C31.686,16.0188 30.4153,15.2885 29.0136,15.0483C27.612,14.8081 26.1706,15.0735 24.9464,15.7973C23.7223,16.5211 22.795,17.6561 22.33,19C22.2199,19.3261 22.1363,19.6605 22.08,20"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index 7f8d4fa..9972496 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -15,5 +15,5 @@
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/android_11_dial"/>
+ <foreground android:drawable="@drawable/android_12"/>
</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
index 31b2a7f..ff7cbae 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#073042" />
+ android:color="@android:color/system_accent1_500" />
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 20b3eb1..5ef7143 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2407,8 +2407,10 @@
if (isEncryptedOrLockdown(userId) && supportsFaceDetection) {
mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
} else {
+ final boolean isBypassEnabled = mKeyguardBypassController != null
+ && mKeyguardBypassController.isBypassEnabled();
mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
- mFaceAuthenticationCallback, null /* handler */, userId);
+ mFaceAuthenticationCallback, null /* handler */, userId, isBypassEnabled);
}
setFaceRunningState(BIOMETRIC_STATE_RUNNING);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index e272d27..222ed63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -18,10 +18,7 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
-import android.animation.ValueAnimator;
import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.Configuration;
@@ -46,35 +43,17 @@
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
-import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
-import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
-import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
/**
* The header group on Keyguard.
*/
-public class KeyguardStatusBarView extends RelativeLayout implements
- BatteryStateChangeCallback,
- OnUserInfoChangedListener,
- ConfigurationListener,
- SystemStatusAnimationCallback {
+public class KeyguardStatusBarView extends RelativeLayout {
private static final int LAYOUT_NONE = 0;
private static final int LAYOUT_CUTOUT = 1;
@@ -84,30 +63,23 @@
private boolean mShowPercentAvailable;
private boolean mBatteryCharging;
- private boolean mBatteryListening;
private TextView mCarrierLabel;
private ImageView mMultiUserAvatar;
private BatteryMeterView mBatteryView;
private StatusIconContainer mStatusIconContainer;
- private BatteryController mBatteryController;
private boolean mKeyguardUserSwitcherEnabled;
private final UserManager mUserManager;
private int mSystemIconsSwitcherHiddenExpandedMargin;
private int mSystemIconsBaseMargin;
private View mSystemIconsContainer;
- private TintedIconManager mIconManager;
- private List<String> mBlockedIcons = new ArrayList<>();
private View mCutoutSpace;
private ViewGroup mStatusIconArea;
private int mLayoutState = LAYOUT_NONE;
- private SystemStatusAnimationScheduler mAnimationScheduler;
- private FeatureFlags mFeatureFlags;
-
/**
* Draw this many pixels into the left/right side of the cutout to optimally use the space
*/
@@ -141,10 +113,6 @@
mStatusIconContainer = findViewById(R.id.statusIcons);
loadDimens();
- loadBlockList();
- mBatteryController = Dependency.get(BatteryController.class);
- mAnimationScheduler = Dependency.get(SystemStatusAnimationScheduler.class);
- mFeatureFlags = Dependency.get(FeatureFlags.class);
}
@Override
@@ -190,7 +158,7 @@
setLayoutParams(lp);
}
- private void loadDimens() {
+ void loadDimens() {
Resources res = getResources();
mSystemIconsSwitcherHiddenExpandedMargin = res.getDimensionPixelSize(
R.dimen.system_icons_switcher_hidden_expanded_margin);
@@ -204,14 +172,6 @@
R.dimen.rounded_corner_content_padding);
}
- // Set hidden status bar items
- private void loadBlockList() {
- Resources r = getResources();
- mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_volume));
- mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_alarm_clock));
- mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_call_strength));
- }
-
private void updateVisibilities() {
if (mMultiUserAvatar.getParent() != mStatusIconArea
&& !mKeyguardUserSwitcherEnabled) {
@@ -348,59 +308,19 @@
return true;
}
- public void setListening(boolean listening) {
- if (listening == mBatteryListening) {
- return;
- }
- mBatteryListening = listening;
- if (mBatteryListening) {
- mBatteryController.addCallback(this);
- } else {
- mBatteryController.removeCallback(this);
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- UserInfoController userInfoController = Dependency.get(UserInfoController.class);
- userInfoController.addCallback(this);
- userInfoController.reloadUserInfo();
- Dependency.get(ConfigurationController.class).addCallback(this);
- mIconManager = new TintedIconManager(findViewById(R.id.statusIcons), mFeatureFlags);
- mIconManager.setBlockList(mBlockedIcons);
- Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
- mAnimationScheduler.addCallback(this);
- onThemeChanged();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- Dependency.get(UserInfoController.class).removeCallback(this);
- Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
- Dependency.get(ConfigurationController.class).removeCallback(this);
- mAnimationScheduler.removeCallback(this);
- }
-
- @Override
- public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onUserInfoChanged(Drawable picture) {
mMultiUserAvatar.setImageDrawable(picture);
}
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onBatteryLevelChanged(boolean charging) {
if (mBatteryCharging != charging) {
mBatteryCharging = charging;
updateVisibilities();
}
}
- @Override
- public void onPowerSaveChanged(boolean isPowerSave) {
- // could not care less
- }
-
public void setKeyguardUserSwitcherEnabled(boolean enabled) {
mKeyguardUserSwitcherEnabled = enabled;
}
@@ -467,28 +387,20 @@
return false;
}
- public void onThemeChanged() {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onThemeChanged(StatusBarIconController.TintedIconManager iconManager) {
mBatteryView.setColorsFromContext(mContext);
- updateIconsAndTextColors();
- // Reload user avatar
- ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
- .onDensityOrFontScaleChanged();
+ updateIconsAndTextColors(iconManager);
}
- @Override
- public void onDensityOrFontScaleChanged() {
- loadDimens();
- }
-
- @Override
- public void onOverlayChanged() {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void onOverlayChanged() {
mCarrierLabel.setTextAppearance(
Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall));
- onThemeChanged();
mBatteryView.updatePercentView();
}
- private void updateIconsAndTextColors() {
+ private void updateIconsAndTextColors(StatusBarIconController.TintedIconManager iconManager) {
@ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext,
R.attr.wallpaperTextColor);
@ColorInt int iconColor = Utils.getColorStateListDefaultColor(mContext,
@@ -496,8 +408,8 @@
R.color.light_mode_icon_color_single_tone);
float intensity = textColor == Color.WHITE ? 0 : 1;
mCarrierLabel.setTextColor(iconColor);
- if (mIconManager != null) {
- mIconManager.setTint(iconColor);
+ if (iconManager != null) {
+ iconManager.setTint(iconColor);
}
applyDarkness(R.id.battery, mEmptyRect, intensity, iconColor);
@@ -522,10 +434,10 @@
}
}
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardStatusBarView:");
pw.println(" mBatteryCharging: " + mBatteryCharging);
- pw.println(" mBatteryListening: " + mBatteryListening);
pw.println(" mLayoutState: " + mLayoutState);
pw.println(" mKeyguardUserSwitcherEnabled: " + mKeyguardUserSwitcherEnabled);
if (mBatteryView != null) {
@@ -533,19 +445,16 @@
}
}
- /** SystemStatusAnimationCallback */
- @Override
- public void onSystemChromeAnimationStart() {
- if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT) {
+ void onSystemChromeAnimationStart(boolean isAnimatingOut) {
+ if (isAnimatingOut) {
mSystemIconsContainer.setVisibility(View.VISIBLE);
mSystemIconsContainer.setAlpha(0f);
}
}
- @Override
- public void onSystemChromeAnimationEnd() {
+ void onSystemChromeAnimationEnd(boolean isAnimatingIn) {
// Make sure the system icons are out of the way
- if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
+ if (isAnimatingIn) {
mSystemIconsContainer.setVisibility(View.INVISIBLE);
mSystemIconsContainer.setAlpha(0f);
} else {
@@ -554,9 +463,8 @@
}
}
- @Override
- public void onSystemChromeAnimationUpdate(ValueAnimator anim) {
- mSystemIconsContainer.setAlpha((float) anim.getAnimatedValue());
+ void onSystemChromeAnimationUpdate(float animatedValue) {
+ mSystemIconsContainer.setAlpha(animatedValue);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 377fb92..5d8d36e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -16,20 +16,120 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
+
+import android.animation.ValueAnimator;
+import android.content.res.Resources;
+
+import androidx.annotation.NonNull;
+
import com.android.keyguard.CarrierTextController;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.util.ViewController;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import javax.inject.Inject;
/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
private final CarrierTextController mCarrierTextController;
+ private final ConfigurationController mConfigurationController;
+ private final SystemStatusAnimationScheduler mAnimationScheduler;
+ private final BatteryController mBatteryController;
+ private final UserInfoController mUserInfoController;
+ private final StatusBarIconController mStatusBarIconController;
+ private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
+
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ mView.loadDimens();
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ KeyguardStatusBarViewController.this.onThemeChanged();
+ mView.onOverlayChanged();
+ }
+
+ @Override
+ public void onThemeChanged() {
+ KeyguardStatusBarViewController.this.onThemeChanged();
+ }
+ };
+
+ private final SystemStatusAnimationCallback mAnimationCallback =
+ new SystemStatusAnimationCallback() {
+ @Override
+ public void onSystemChromeAnimationStart() {
+ mView.onSystemChromeAnimationStart(
+ mAnimationScheduler.getAnimationState() == ANIMATING_OUT);
+ }
+
+ @Override
+ public void onSystemChromeAnimationEnd() {
+ mView.onSystemChromeAnimationEnd(
+ mAnimationScheduler.getAnimationState() == ANIMATING_IN);
+ }
+
+ @Override
+ public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator anim) {
+ mView.onSystemChromeAnimationUpdate((float) anim.getAnimatedValue());
+ }
+ };
+
+ private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback =
+ new BatteryController.BatteryStateChangeCallback() {
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ mView.onBatteryLevelChanged(charging);
+ }
+ };
+
+ private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
+ (name, picture, userAccount) -> mView.onUserInfoChanged(picture);
+
+ private final List<String> mBlockedIcons;
+
+ private boolean mBatteryListening;
+ private StatusBarIconController.TintedIconManager mTintedIconManager;
@Inject
public KeyguardStatusBarViewController(
- KeyguardStatusBarView view, CarrierTextController carrierTextController) {
+ KeyguardStatusBarView view,
+ CarrierTextController carrierTextController,
+ ConfigurationController configurationController,
+ SystemStatusAnimationScheduler animationScheduler,
+ BatteryController batteryController,
+ UserInfoController userInfoController,
+ StatusBarIconController statusBarIconController,
+ StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory) {
super(view);
mCarrierTextController = carrierTextController;
+ mConfigurationController = configurationController;
+ mAnimationScheduler = animationScheduler;
+ mBatteryController = batteryController;
+ mUserInfoController = userInfoController;
+ mStatusBarIconController = statusBarIconController;
+ mTintedIconManagerFactory = tintedIconManagerFactory;
+
+ Resources r = getResources();
+ mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
+ r.getString(com.android.internal.R.string.status_bar_volume),
+ r.getString(com.android.internal.R.string.status_bar_alarm_clock),
+ r.getString(com.android.internal.R.string.status_bar_call_strength)));
}
@Override
@@ -40,9 +140,55 @@
@Override
protected void onViewAttached() {
+ mConfigurationController.addCallback(mConfigurationListener);
+ mAnimationScheduler.addCallback(mAnimationCallback);
+ mUserInfoController.addCallback(mOnUserInfoChangedListener);
+ if (mTintedIconManager == null) {
+ mTintedIconManager =
+ mTintedIconManagerFactory.create(mView.findViewById(R.id.statusIcons));
+ mTintedIconManager.setBlockList(mBlockedIcons);
+ mStatusBarIconController.addIconGroup(mTintedIconManager);
+ }
+ onThemeChanged();
}
@Override
protected void onViewDetached() {
+ // Don't receive future #onViewAttached calls so that we don't accidentally have two
+ // controllers registered for the same view.
+ // TODO(b/194181195): This shouldn't be necessary.
+ destroy();
+
+ mConfigurationController.removeCallback(mConfigurationListener);
+ mAnimationScheduler.removeCallback(mAnimationCallback);
+ mUserInfoController.removeCallback(mOnUserInfoChangedListener);
+ if (mTintedIconManager != null) {
+ mStatusBarIconController.removeIconGroup(mTintedIconManager);
+ }
+ }
+
+ /** Should be called when the theme changes. */
+ public void onThemeChanged() {
+ mView.onThemeChanged(mTintedIconManager);
+ }
+
+ /** Sets whether this controller should listen to battery updates. */
+ public void setBatteryListening(boolean listening) {
+ if (listening == mBatteryListening) {
+ return;
+ }
+ mBatteryListening = listening;
+ if (mBatteryListening) {
+ mBatteryController.addCallback(mBatteryStateChangeCallback);
+ } else {
+ mBatteryController.removeCallback(mBatteryStateChangeCallback);
+ }
+ }
+
+ /** */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("KeyguardStatusBarView:");
+ pw.println(" mBatteryListening: " + mBatteryListening);
+ mView.dump(fd, pw, args);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 67fa796..481a8ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -356,7 +356,7 @@
private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
private KeyguardStatusBarView mKeyguardStatusBar;
- private KeyguardStatusBarViewController mKeyguarStatusBarViewController;
+ private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
private ViewGroup mBigClockContainer;
@VisibleForTesting QS mQs;
private FrameLayout mQsFrame;
@@ -1012,9 +1012,13 @@
KeyguardStatusBarViewComponent statusBarViewComponent =
mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView);
- mKeyguarStatusBarViewController =
+ if (mKeyguardStatusBarViewController != null) {
+ // TODO(b/194181195): This shouldn't be necessary.
+ mKeyguardStatusBarViewController.onViewDetached();
+ }
+ mKeyguardStatusBarViewController =
statusBarViewComponent.getKeyguardStatusBarViewController();
- mKeyguarStatusBarViewController.init();
+ mKeyguardStatusBarViewController.init();
if (communalView != null) {
CommunalViewComponent communalViewComponent =
@@ -1199,10 +1203,6 @@
mStatusBarStateListener.onDozeAmountChanged(mStatusBarStateController.getDozeAmount(),
mStatusBarStateController.getInterpolatedDozeAmount());
- if (mKeyguardStatusBar != null) {
- mKeyguardStatusBar.onThemeChanged();
- }
-
mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
mBarState,
false,
@@ -3211,7 +3211,7 @@
}
private void setListening(boolean listening) {
- mKeyguardStatusBar.setListening(listening);
+ mKeyguardStatusBarViewController.setBatteryListening(listening);
if (mQs == null) return;
mQs.setListening(listening);
}
@@ -3855,8 +3855,8 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
super.dump(fd, pw, args);
pw.println(" gestureExclusionRect: " + calculateGestureExclusionRect());
- if (mKeyguardStatusBar != null) {
- mKeyguardStatusBar.dump(fd, pw, args);
+ if (mKeyguardStatusBarViewController != null) {
+ mKeyguardStatusBarViewController.dump(fd, pw, args);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index a9e949c..b51572e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3964,7 +3964,11 @@
|| !wakingUp && mWakefulnessLifecycle.getLastSleepReason()
== PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
mLightRevealScrim.setRevealEffect(mPowerButtonReveal);
- } else if (!(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
+ } else if (!wakingUp || !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
+ // If we're going to sleep, but it's not from the power button, use the default reveal.
+ // If we're waking up, only use the default reveal if the biometric controller didn't
+ // already set it to the circular reveal because we're waking up from a fingerprint/face
+ // auth.
mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 2c75534..dbe4c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -35,6 +35,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
@@ -50,6 +51,8 @@
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+
public interface StatusBarIconController {
/**
@@ -213,6 +216,20 @@
icons.setColor(mColor);
return icons;
}
+
+ @SysUISingleton
+ public static class Factory {
+ private final FeatureFlags mFeatureFlags;
+
+ @Inject
+ public Factory(FeatureFlags featureFlags) {
+ mFeatureFlags = featureFlags;
+ }
+
+ public TintedIconManager create(ViewGroup group) {
+ return new TintedIconManager(group, mFeatureFlags);
+ }
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 75900a2..9d1c1e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -23,6 +23,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.view.ViewGroup;
import com.android.internal.statusbar.StatusBarIcon;
@@ -88,6 +89,13 @@
/** */
@Override
public void addIconGroup(IconManager group) {
+ for (IconManager existingIconManager : mIconGroups) {
+ if (existingIconManager.mGroup == group.mGroup) {
+ Log.e(TAG, "Adding new IconManager for the same ViewGroup. This could cause "
+ + "unexpected results.");
+ }
+ }
+
mIconGroups.add(group);
List<Slot> allSlots = getSlots();
for (int i = 0; i < allSlots.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index 0dd5788..32bbe1c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -110,6 +110,16 @@
}
/**
+ * Destroys this controller so that it never receives view attach and detach events again.
+ * Does nothing if the view is null.
+ */
+ public void destroy() {
+ if (mView != null) {
+ mView.removeOnAttachStateChangeListener(mOnAttachStateListener);
+ }
+ }
+
+ /**
* Called when the view is attached and a call to {@link #init()} has been made in either order.
*/
protected abstract void onViewAttached();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index e9061af..ec4dfba 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -513,7 +513,7 @@
public void testTriesToAuthenticate_whenBouncer() {
setKeyguardBouncerVisibility(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).isHardwareDetected();
verify(mFaceManager).hasEnrolledTemplates(anyInt());
}
@@ -523,7 +523,7 @@
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -533,7 +533,8 @@
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -545,7 +546,8 @@
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -568,13 +570,14 @@
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
// Stop scanning when bouncer becomes visible
setKeyguardBouncerVisibility(true);
clearInvocations(mFaceManager);
mKeyguardUpdateMonitor.requestFaceAuth(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -582,7 +585,7 @@
mKeyguardUpdateMonitor.setKeyguardOccluded(true);
mKeyguardUpdateMonitor.setAssistantVisible(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -594,7 +597,7 @@
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -604,7 +607,8 @@
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -615,7 +619,8 @@
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
@@ -626,7 +631,7 @@
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -638,7 +643,8 @@
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
mTestableLooper.processAllMessages();
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
new file mode 100644
index 0000000..217a77d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2021 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.statusbar.phone;
+
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.CarrierTextController;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
+ @Mock
+ private KeyguardStatusBarView mKeyguardStatusBarView;
+ @Mock
+ private ViewGroup mViewGroup;
+ @Mock
+ private CarrierTextController mCarrierTextController;
+ @Mock
+ private ConfigurationController mConfigurationController;
+ @Mock
+ private SystemStatusAnimationScheduler mAnimationScheduler;
+ @Mock
+ private BatteryController mBatteryController;
+ @Mock
+ private UserInfoController mUserInfoController;
+ @Mock
+ private StatusBarIconController mStatusBarIconController;
+ @Mock
+ private FeatureFlags mFeatureFlags;
+
+ private KeyguardStatusBarViewController mController;
+
+ @Before
+ public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mKeyguardStatusBarView.getResources()).thenReturn(mContext.getResources());
+ when(mKeyguardStatusBarView.findViewById(R.id.statusIcons)).thenReturn(mViewGroup);
+ when(mViewGroup.getContext()).thenReturn(mContext);
+
+ mController = new KeyguardStatusBarViewController(
+ mKeyguardStatusBarView,
+ mCarrierTextController,
+ mConfigurationController,
+ mAnimationScheduler,
+ mBatteryController,
+ mUserInfoController,
+ mStatusBarIconController,
+ new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags)
+ );
+ }
+
+ @Test
+ public void onViewAttached_callbacksRegistered() {
+ mController.onViewAttached();
+
+ verify(mConfigurationController).addCallback(any());
+ verify(mAnimationScheduler).addCallback(any());
+ verify(mUserInfoController).addCallback(any());
+ verify(mStatusBarIconController).addIconGroup(any());
+ }
+
+ @Test
+ public void onViewDetached_callbacksUnregistered() {
+ // Set everything up first.
+ mController.onViewAttached();
+
+ mController.onViewDetached();
+
+ verify(mConfigurationController).removeCallback(any());
+ verify(mAnimationScheduler).removeCallback(any());
+ verify(mUserInfoController).removeCallback(any());
+ verify(mStatusBarIconController).removeIconGroup(any());
+ }
+
+ @Test
+ public void setBatteryListening_true_callbackAdded() {
+ mController.setBatteryListening(true);
+
+ verify(mBatteryController).addCallback(any());
+ }
+
+ @Test
+ public void setBatteryListening_false_callbackRemoved() {
+ // First set to true so that we know setting to false is a change in state.
+ mController.setBatteryListening(true);
+
+ mController.setBatteryListening(false);
+
+ verify(mBatteryController).removeCallback(any());
+ }
+
+ @Test
+ public void setBatteryListening_trueThenTrue_callbackAddedOnce() {
+ mController.setBatteryListening(true);
+ mController.setBatteryListening(true);
+
+ verify(mBatteryController).addCallback(any());
+ }
+}
diff --git a/services/core/java/com/android/server/PermissionThread.java b/services/core/java/com/android/server/PermissionThread.java
new file mode 100644
index 0000000..cf444fa
--- /dev/null
+++ b/services/core/java/com/android/server/PermissionThread.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
+import android.os.Trace;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.ServiceThread;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Shared singleton thread for the system. This is a thread for handling
+ * calls to and from the PermissionController and handling synchronization
+ * between permissions and appops states.
+ */
+public final class PermissionThread extends ServiceThread {
+ private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
+ private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
+
+ private static final Object sLock = new Object();
+
+ @GuardedBy("sLock")
+ private static PermissionThread sInstance;
+ private static Handler sHandler;
+ private static HandlerExecutor sHandlerExecutor;
+
+ private PermissionThread() {
+ super("android.perm", android.os.Process.THREAD_PRIORITY_DEFAULT, /* allowIo= */ true);
+ }
+
+ private static void ensureThreadLocked() {
+ if (sInstance != null) {
+ return;
+ }
+
+ sInstance = new PermissionThread();
+ sInstance.start();
+ final Looper looper = sInstance.getLooper();
+ looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
+ looper.setSlowLogThresholdMs(
+ SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
+ sHandler = new Handler(sInstance.getLooper());
+ sHandlerExecutor = new HandlerExecutor(sHandler);
+ }
+
+ public static PermissionThread get() {
+ synchronized (sLock) {
+ ensureThreadLocked();
+ return sInstance;
+ }
+ }
+
+ public static Handler getHandler() {
+ synchronized (sLock) {
+ ensureThreadLocked();
+ return sHandler;
+ }
+ }
+
+ public static Executor getExecutor() {
+ synchronized (sLock) {
+ ensureThreadLocked();
+ return sHandlerExecutor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 6b7787a..4973d45 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -1103,9 +1103,8 @@
}
public boolean isAdvancedCoexLogicEnabled(Context context) {
- return (Build.IS_USERDEBUG || Build.IS_ENG)
- && Settings.Secure.getInt(context.getContentResolver(),
- CoexCoordinator.SETTING_ENABLE_NAME, 0) != 0;
+ return Settings.Secure.getInt(context.getContentResolver(),
+ CoexCoordinator.SETTING_ENABLE_NAME, 1) != 0;
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 6463e04..013c74d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -70,6 +70,7 @@
private final LockoutTracker mLockoutTracker;
private final boolean mIsRestricted;
private final boolean mAllowBackgroundAuthentication;
+ private final boolean mIsKeyguardBypassEnabled;
protected final long mOperationId;
@@ -97,7 +98,7 @@
int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,
int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication,
- boolean shouldVibrate) {
+ boolean shouldVibrate, boolean isKeyguardBypassEnabled) {
super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
shouldVibrate, statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE,
statsClient);
@@ -110,6 +111,7 @@
mLockoutTracker = lockoutTracker;
mIsRestricted = restricted;
mAllowBackgroundAuthentication = allowBackgroundAuthentication;
+ mIsKeyguardBypassEnabled = isKeyguardBypassEnabled;
}
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
@@ -394,6 +396,14 @@
return mState;
}
+ /**
+ * @return true if the client supports bypass (e.g. passive auth such as face), and if it's
+ * enabled by the user.
+ */
+ public boolean isKeyguardBypassEnabled() {
+ return mIsKeyguardBypassEnabled;
+ }
+
@Override
public int getProtoEnum() {
return BiometricsProto.CM_AUTHENTICATE;
diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
index f732a14..b576673 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -26,7 +26,6 @@
import android.os.Looper;
import android.util.Slog;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.sensors.BiometricScheduler.SensorType;
import com.android.server.biometrics.sensors.fingerprint.Udfps;
@@ -242,6 +241,11 @@
callback.sendHapticFeedback();
callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
callback.handleLifecycleAfterAuth();
+ } else {
+ // Capacitive fingerprint sensor (or other)
+ callback.sendHapticFeedback();
+ callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
}
}
} else {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 219e063..12d6b08 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -251,7 +251,8 @@
@Override // Binder call
public void authenticate(final IBinder token, final long operationId, int userId,
- final IFaceServiceReceiver receiver, final String opPackageName) {
+ final IFaceServiceReceiver receiver, final String opPackageName,
+ boolean isKeyguardBypassEnabled) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
// TODO(b/152413782): If the sensor supports face detect and the device is encrypted or
@@ -275,7 +276,7 @@
provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */,
new ClientMonitorCallbackConverter(receiver), opPackageName, restricted,
- statsClient, isKeyguard);
+ statsClient, isKeyguard, isKeyguardBypassEnabled);
}
@Override // Binder call
@@ -318,10 +319,12 @@
return;
}
+ final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients
final boolean restricted = true; // BiometricPrompt is always restricted
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
- BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication);
+ BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication,
+ isKeyguardBypassEnabled);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 1d2ac3b..93ab1b6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -110,7 +110,7 @@
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication);
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
void cancelAuthentication(int sensorId, @NonNull IBinder token);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 0c06b20..f7fd8d0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -69,11 +69,13 @@
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
- @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication) {
+ @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication,
+ boolean isKeyguardBypassEnabled) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
- lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
+ isKeyguardBypassEnabled);
mUsageStats = usageStats;
mLockoutCache = lockoutCache;
mNotificationManager = context.getSystemService(NotificationManager.class);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 5c24108..718b9da 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -378,7 +378,7 @@
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication) {
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(
@@ -386,7 +386,7 @@
operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
- allowBackgroundAuthentication);
+ allowBackgroundAuthentication, isKeyguardBypassEnabled);
scheduleForSensor(sensorId, client);
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index da4ad86..d05333d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -622,7 +622,7 @@
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication) {
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -630,7 +630,8 @@
final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName,
cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric,
- statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication);
+ statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication,
+ isKeyguardBypassEnabled);
mScheduler.scheduleClientMonitor(client);
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 868f379..c33b957 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -61,11 +61,13 @@
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker,
- @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication) {
+ @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication,
+ boolean isKeyguardBypassEnabled) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
- lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
+ isKeyguardBypassEnabled);
mUsageStats = usageStats;
final Resources resources = getContext().getResources();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index fb2f2ef..99e6e62 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -72,7 +72,8 @@
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
- lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
mLockoutCache = lockoutCache;
mUdfpsOverlayController = udfpsOverlayController;
mSensorProps = sensorProps;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 5c9a764..7558d15 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -71,7 +71,8 @@
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
- lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */);
+ lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
mLockoutFrameworkImpl = lockoutTracker;
mUdfpsOverlayController = udfpsOverlayController;
mSensorProps = sensorProps;
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index 4bbe373..dd50b0c 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -33,6 +33,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.PermissionThread;
/**
* Class that handles one-time permissions for a user
@@ -79,7 +80,8 @@
mContext = context;
mActivityManager = context.getSystemService(ActivityManager.class);
mAlarmManager = context.getSystemService(AlarmManager.class);
- mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class);
+ mPermissionControllerManager = new PermissionControllerManager(
+ mContext, PermissionThread.getHandler());
mHandler = context.getMainThreadHandler();
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index fbe14ce..b619a9d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -145,6 +145,7 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.PermissionThread;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
@@ -2056,7 +2057,7 @@
private byte[] backupRuntimePermissions(@UserIdInt int userId) {
CompletableFuture<byte[]> backup = new CompletableFuture<>();
mPermissionControllerManager.getRuntimePermissionBackup(UserHandle.of(userId),
- mContext.getMainExecutor(), backup::complete);
+ PermissionThread.getExecutor(), backup::complete);
try {
return backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
@@ -2101,7 +2102,7 @@
}
}
mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName,
- UserHandle.of(userId), mContext.getMainExecutor(), (hasMoreBackup) -> {
+ UserHandle.of(userId), PermissionThread.getExecutor(), (hasMoreBackup) -> {
if (hasMoreBackup) {
return;
}
@@ -4548,7 +4549,8 @@
}
}
- mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
+ mPermissionControllerManager = new PermissionControllerManager(
+ mContext, PermissionThread.getHandler());
mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
}
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index ad43514..2709d4f 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -64,8 +64,8 @@
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.PermissionThread;
import com.android.server.SystemService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -279,7 +279,7 @@
PermissionControllerManager manager = mPermControllerManagers.get(user);
if (manager == null) {
manager = new PermissionControllerManager(
- getUserContext(getContext(), user), FgThread.getHandler());
+ getUserContext(getContext(), user), PermissionThread.getHandler());
mPermControllerManagers.put(user, manager);
}
manager.updateUserSensitiveForApp(uid);
@@ -287,8 +287,9 @@
}, UserHandle.ALL, intentFilter, null, null);
PermissionControllerManager manager = new PermissionControllerManager(
- getUserContext(getContext(), Process.myUserHandle()), FgThread.getHandler());
- FgThread.getHandler().postDelayed(manager::updateUserSensitive,
+ getUserContext(getContext(), Process.myUserHandle()),
+ PermissionThread.getHandler());
+ PermissionThread.getHandler().postDelayed(manager::updateUserSensitive,
USER_SENSITIVE_UPDATE_DELAY_MS);
}
@@ -315,7 +316,7 @@
if (isStarted(changedUserId)) {
synchronized (mLock) {
if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
- FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage(
PermissionPolicyService
::synchronizePackagePermissionsAndAppOpsForUser,
this, packageName, changedUserId));
@@ -421,9 +422,9 @@
final PermissionControllerManager permissionControllerManager =
new PermissionControllerManager(
getUserContext(getContext(), UserHandle.of(userId)),
- FgThread.getHandler());
+ PermissionThread.getHandler());
permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
- FgThread.getExecutor(), successful -> {
+ PermissionThread.getExecutor(), successful -> {
if (successful) {
future.complete(null);
} else {
@@ -527,7 +528,7 @@
synchronized (mLock) {
if (!mIsUidSyncScheduled.get(uid)) {
mIsUidSyncScheduled.put(uid, true);
- FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage(
PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid,
this, uid));
}
diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java
index fe977f8..ac2d76e 100644
--- a/services/core/java/com/android/server/timedetector/ServerFlags.java
+++ b/services/core/java/com/android/server/timedetector/ServerFlags.java
@@ -28,8 +28,10 @@
import com.android.server.timezonedetector.ConfigurationChangeListener;
import com.android.server.timezonedetector.ServiceConfigAccessor;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.time.DateTimeException;
import java.time.Duration;
import java.time.Instant;
@@ -63,6 +65,7 @@
KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE,
KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE,
})
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
@Retention(RetentionPolicy.SOURCE)
@interface DeviceConfigKey {}
@@ -72,40 +75,39 @@
* {@link ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupportedInConfig()} and {@link
* ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupported()}.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED =
+ public static final @DeviceConfigKey String KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED =
"location_time_zone_detection_feature_supported";
/**
* The key for the server flag that can override the device config for whether the primary
* location time zone provider is enabled, disabled, or (for testing) in simulation mode.
*/
- @DeviceConfigKey
- public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
+ public static final @DeviceConfigKey String
+ KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
"primary_location_time_zone_provider_mode_override";
/**
* The key for the server flag that can override the device config for whether the secondary
* location time zone provider is enabled or disabled, or (for testing) in simulation mode.
*/
- @DeviceConfigKey
- public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
+ public static final @DeviceConfigKey String
+ KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
"secondary_location_time_zone_provider_mode_override";
/**
* The key for the minimum delay after location time zone detection has been enabled before the
* location time zone manager can report it is uncertain about the time zone.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS =
"location_time_zone_detection_uncertainty_delay_millis";
/**
* The key for the timeout passed to a location time zone provider that tells it how long it has
* to provide an explicit first suggestion without being declared uncertain.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS =
"ltpz_init_timeout_millis";
/**
@@ -113,8 +115,8 @@
* #KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS} by the location time zone
* manager before the location time zone provider will actually be declared uncertain.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS =
"ltpz_init_timeout_fuzz_millis";
/**
@@ -123,16 +125,16 @@
* disable the feature by turning off the master location switch, or by disabling automatic time
* zone detection.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE =
"location_time_zone_detection_setting_enabled_override";
/**
* The key for the default value used to determine whether location time zone detection is
* enabled when the user hasn't explicitly set it yet.
*/
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT =
+ public static final @DeviceConfigKey String
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT =
"location_time_zone_detection_setting_enabled_default";
/**
@@ -140,16 +142,14 @@
* of strings that will be passed to {@link TimeDetectorStrategy#stringToOrigin(String)}.
* All values must be recognized or the override value will be ignored.
*/
- @DeviceConfigKey
- public static final String KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE =
+ public static final @DeviceConfigKey String KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE =
"time_detector_origin_priorities_override";
/**
* The key to override the time detector lower bound configuration. The values is the number of
* milliseconds since the beginning of the Unix epoch.
*/
- @DeviceConfigKey
- public static final String KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE =
+ public static final @DeviceConfigKey String KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE =
"time_detector_lower_bound_millis_override";
@GuardedBy("mListeners")
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index ff5060e..acabb6e 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -53,24 +53,19 @@
@interface Origin {}
/** Used when a time value originated from a telephony signal. */
- @Origin
- int ORIGIN_TELEPHONY = 1;
+ @Origin int ORIGIN_TELEPHONY = 1;
/** Used when a time value originated from a user / manual settings. */
- @Origin
- int ORIGIN_MANUAL = 2;
+ @Origin int ORIGIN_MANUAL = 2;
/** Used when a time value originated from a network signal. */
- @Origin
- int ORIGIN_NETWORK = 3;
+ @Origin int ORIGIN_NETWORK = 3;
/** Used when a time value originated from a gnss signal. */
- @Origin
- int ORIGIN_GNSS = 4;
+ @Origin int ORIGIN_GNSS = 4;
/** Used when a time value originated from an externally specified signal. */
- @Origin
- int ORIGIN_EXTERNAL = 5;
+ @Origin int ORIGIN_EXTERNAL = 5;
/** Processes the suggested time from telephony sources. */
void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion);
diff --git a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
index 27b50d8..9eb6a45 100644
--- a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
+++ b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
@@ -26,6 +26,10 @@
import android.util.proto.ProtoOutputStream;
import java.io.ByteArrayOutputStream;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -44,14 +48,13 @@
@IntDef(prefix = "DETECTION_MODE_",
value = { DETECTION_MODE_MANUAL, DETECTION_MODE_GEO, DETECTION_MODE_TELEPHONY})
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
@interface DetectionMode {};
- @DetectionMode
- public static final int DETECTION_MODE_MANUAL = 0;
- @DetectionMode
- public static final int DETECTION_MODE_GEO = 1;
- @DetectionMode
- public static final int DETECTION_MODE_TELEPHONY = 2;
+ public static final @DetectionMode int DETECTION_MODE_MANUAL = 0;
+ public static final @DetectionMode int DETECTION_MODE_GEO = 1;
+ public static final @DetectionMode int DETECTION_MODE_TELEPHONY = 2;
@NonNull
private final ConfigurationInternal mConfigurationInternal;
@@ -132,8 +135,7 @@
* Returns the detection mode the device is currently using, which can be influenced by various
* things besides the user's setting.
*/
- @DetectionMode
- public int getDetectionMode() {
+ public @DetectionMode int getDetectionMode() {
if (!mConfigurationInternal.getAutoDetectionEnabledBehavior()) {
return DETECTION_MODE_MANUAL;
} else if (mConfigurationInternal.getGeoDetectionEnabledBehavior()) {
diff --git a/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
index 5087530..dfefb8f 100644
--- a/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
+++ b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
@@ -33,7 +33,7 @@
class OrdinalGenerator<T> {
private final ArraySet<T> mKnownIds = new ArraySet<>();
- private final @NonNull Function<T, T> mCanonicalizationFunction;
+ @NonNull private final Function<T, T> mCanonicalizationFunction;
OrdinalGenerator(@NonNull Function<T, T> canonicalizationFunction) {
mCanonicalizationFunction = Objects.requireNonNull(canonicalizationFunction);
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
index 23f6bbe..2be8e35 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -48,7 +48,7 @@
@StringDef(prefix = "PROVIDER_MODE_",
value = { PROVIDER_MODE_SIMULATED, PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED})
@Retention(RetentionPolicy.SOURCE)
- @Target(ElementType.TYPE_USE)
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
@interface ProviderMode {}
/**
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
index c2add2d..c0fd6b1 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
@@ -48,6 +48,10 @@
import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
import com.android.server.timezonedetector.location.ThreadingDomain.SingleRunnableQueue;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -101,34 +105,36 @@
value = { PROVIDER_STATE_UNKNOWN, PROVIDER_STATE_STARTED_INITIALIZING,
PROVIDER_STATE_STARTED_CERTAIN, PROVIDER_STATE_STARTED_UNCERTAIN,
PROVIDER_STATE_STOPPED, PROVIDER_STATE_PERM_FAILED, PROVIDER_STATE_DESTROYED })
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
@interface ProviderStateEnum {}
/**
* Uninitialized value. Must not be used afte {@link LocationTimeZoneProvider#initialize}.
*/
- static final int PROVIDER_STATE_UNKNOWN = 0;
+ static final @ProviderStateEnum int PROVIDER_STATE_UNKNOWN = 0;
/**
* The provider is started and has not reported its first event.
*/
- static final int PROVIDER_STATE_STARTED_INITIALIZING = 1;
+ static final @ProviderStateEnum int PROVIDER_STATE_STARTED_INITIALIZING = 1;
/**
* The provider is started and most recently reported a "suggestion" event.
*/
- static final int PROVIDER_STATE_STARTED_CERTAIN = 2;
+ static final @ProviderStateEnum int PROVIDER_STATE_STARTED_CERTAIN = 2;
/**
* The provider is started and most recently reported an "uncertain" event.
*/
- static final int PROVIDER_STATE_STARTED_UNCERTAIN = 3;
+ static final @ProviderStateEnum int PROVIDER_STATE_STARTED_UNCERTAIN = 3;
/**
* The provider is stopped.
*
* This is the state after {@link #initialize} is called.
*/
- static final int PROVIDER_STATE_STOPPED = 4;
+ static final @ProviderStateEnum int PROVIDER_STATE_STOPPED = 4;
/**
* The provider has failed and cannot be restarted. This is a terminated state triggered by
@@ -136,16 +142,16 @@
*
* Providers may enter this state any time after a provider is started.
*/
- static final int PROVIDER_STATE_PERM_FAILED = 5;
+ static final @ProviderStateEnum int PROVIDER_STATE_PERM_FAILED = 5;
/**
* The provider has been destroyed by the controller and cannot be restarted. Similar to
* {@link #PROVIDER_STATE_PERM_FAILED} except that a provider is set into this state.
*/
- static final int PROVIDER_STATE_DESTROYED = 6;
+ static final @ProviderStateEnum int PROVIDER_STATE_DESTROYED = 6;
/** The {@link LocationTimeZoneProvider} the state is for. */
- public final @NonNull LocationTimeZoneProvider provider;
+ @NonNull public final LocationTimeZoneProvider provider;
/** The state enum value of the current state. */
public final @ProviderStateEnum int stateEnum;
diff --git a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java
index 3e224e0..7648795 100644
--- a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java
+++ b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java
@@ -22,6 +22,10 @@
import android.service.timezone.TimeZoneProviderService;
import android.service.timezone.TimeZoneProviderSuggestion;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.Objects;
/**
@@ -31,31 +35,32 @@
@IntDef(prefix = "EVENT_TYPE_",
value = { EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUGGESTION, EVENT_TYPE_UNCERTAIN })
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
public @interface EventType {}
/**
* The provider failed permanently. See {@link
* TimeZoneProviderService#reportPermanentFailure(Throwable)}
*/
- public static final int EVENT_TYPE_PERMANENT_FAILURE = 1;
+ public static final @EventType int EVENT_TYPE_PERMANENT_FAILURE = 1;
/**
* The provider made a suggestion. See {@link
* TimeZoneProviderService#reportSuggestion(TimeZoneProviderSuggestion)}
*/
- public static final int EVENT_TYPE_SUGGESTION = 2;
+ public static final @EventType int EVENT_TYPE_SUGGESTION = 2;
/**
* The provider was uncertain about the time zone. See {@link
* TimeZoneProviderService#reportUncertain()}
*/
- public static final int EVENT_TYPE_UNCERTAIN = 3;
+ public static final @EventType int EVENT_TYPE_UNCERTAIN = 3;
private static final TimeZoneProviderEvent UNCERTAIN_EVENT =
new TimeZoneProviderEvent(EVENT_TYPE_UNCERTAIN, null, null);
- @EventType
- private final int mType;
+ private final @EventType int mType;
@Nullable
private final TimeZoneProviderSuggestion mSuggestion;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 1fe4123..8592166a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -360,7 +360,8 @@
false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
- false /* isKeyguard */, true /* shouldVibrate */);
+ false /* isKeyguard */, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
}
@Override
@@ -388,7 +389,8 @@
false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
- false /* isKeyguard */, true /* shouldVibrate */);
+ false /* isKeyguard */, true /* shouldVibrate */,
+ false /* isKeyguardBypassEnabled */);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
index a169ebd..f1adcae 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors;
import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE;
+import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FP_OTHER;
import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS;
import static junit.framework.Assert.assertEquals;
@@ -327,6 +328,49 @@
}
@Test
+ public void testKeyguard_capacitiveAccepted_whenFaceScanning() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> fpClient = mock(AuthenticationClient.class);
+ when(fpClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(fpClient.isKeyguard()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, fpClient);
+
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, fpClient, mCallback);
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
+ public void testKeyguard_capacitiveRejected_whenFaceScanning() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> fpClient = mock(AuthenticationClient.class);
+ when(fpClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(fpClient.isKeyguard()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, fpClient);
+
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, fpClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
public void testNonKeyguard_rejectAndNotLockedOut() {
mCoexCoordinator.reset();