Merge "Add Live Captioning repository" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index d410686..283e429 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4380,6 +4380,7 @@
method public android.transition.TransitionManager getContentTransitionManager();
method @Nullable public android.view.View getCurrentFocus();
method @Deprecated public android.app.FragmentManager getFragmentManager();
+ method @FlaggedApi("android.security.content_uri_permission_apis") @NonNull public android.app.ComponentCaller getInitialCaller();
method public android.content.Intent getIntent();
method @Nullable public Object getLastNonConfigurationInstance();
method @Nullable public String getLaunchedFromPackage();
@@ -5420,6 +5421,12 @@
field public static final int DELIVERY_GROUP_POLICY_MOST_RECENT = 1; // 0x1
}
+ @FlaggedApi("android.security.content_uri_permission_apis") public final class ComponentCaller {
+ ctor public ComponentCaller(@NonNull android.os.IBinder, @Nullable android.os.IBinder);
+ method @Nullable public String getPackage();
+ method public int getUid();
+ }
+
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
ctor public DatePickerDialog(@NonNull android.content.Context);
ctor public DatePickerDialog(@NonNull android.content.Context, @StyleRes int);
@@ -42371,6 +42378,8 @@
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
+ method @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") public void onCreateConferenceComplete(@NonNull android.telecom.Conference);
+ method @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") public void onCreateConnectionComplete(@NonNull android.telecom.Connection);
method @Nullable public android.telecom.Conference onCreateIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2103055..ab9a4ec 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -844,6 +844,7 @@
private IBinder mToken;
private IBinder mAssistToken;
private IBinder mShareableActivityToken;
+ private ComponentCaller mInitialCaller;
@UnsupportedAppUsage
private int mIdent;
@UnsupportedAppUsage
@@ -7031,6 +7032,20 @@
}
/**
+ * Returns the ComponentCaller instance of the app that initially launched this activity.
+ *
+ * <p>Note that calls to {@link #onNewIntent} have no effect on the returned value of this
+ * method.
+ *
+ * @return {@link ComponentCaller} instance
+ * @see ComponentCaller
+ */
+ @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+ public @NonNull ComponentCaller getInitialCaller() {
+ return mInitialCaller;
+ }
+
+ /**
* Control whether this activity's main window is visible. This is intended
* only for the special case of an activity that is not going to show a
* UI itself, but can't just finish prior to onResume() because it needs
@@ -8647,6 +8662,19 @@
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
IBinder shareableActivityToken) {
+ attach(context, aThread, instr, token, ident, application, intent, info, title, parent, id,
+ lastNonConfigurationInstances, config, referrer, voiceInteractor, window,
+ activityConfigCallback, assistToken, shareableActivityToken, null);
+ }
+
+ final void attach(Context context, ActivityThread aThread,
+ Instrumentation instr, IBinder token, int ident,
+ Application application, Intent intent, ActivityInfo info,
+ CharSequence title, Activity parent, String id,
+ NonConfigurationInstances lastNonConfigurationInstances,
+ Configuration config, String referrer, IVoiceInteractor voiceInteractor,
+ Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
+ IBinder shareableActivityToken, IBinder initialCallerInfoAccessToken) {
if (sandboxActivitySdkBasedContext()) {
// Sandbox activities extract a token from the intent's extra to identify the related
// SDK as part of overriding attachBaseContext, then it wraps the passed context in an
@@ -8711,6 +8739,10 @@
getAutofillClientController().onActivityAttached(application);
setContentCaptureOptions(application.getContentCaptureOptions());
+
+ if (android.security.Flags.contentUriPermissionApis()) {
+ mInitialCaller = new ComponentCaller(getActivityToken(), initialCallerInfoAccessToken);
+ }
}
/** @hide */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4c54b03..2c00c99 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -580,6 +580,7 @@
public IBinder shareableActivityToken;
// The token of the TaskFragment that embedded this activity.
@Nullable public IBinder mTaskFragmentToken;
+ public IBinder initialCallerInfoAccessToken;
int ident;
@UnsupportedAppUsage
Intent intent;
@@ -668,7 +669,7 @@
List<ReferrerIntent> pendingNewIntents, SceneTransitionInfo sceneTransitionInfo,
boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble,
- IBinder taskFragmentToken) {
+ IBinder taskFragmentToken, IBinder initialCallerInfoAccessToken) {
this.token = token;
this.assistToken = assistToken;
this.shareableActivityToken = shareableActivityToken;
@@ -685,6 +686,7 @@
this.profilerInfo = profilerInfo;
this.overrideConfig = overrideConfig;
this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo);
+ this.initialCallerInfoAccessToken = initialCallerInfoAccessToken;
mSceneTransitionInfo = sceneTransitionInfo;
mLaunchedFromBubble = launchedFromBubble;
mTaskFragmentToken = taskFragmentToken;
@@ -3914,7 +3916,7 @@
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
- r.assistToken, r.shareableActivityToken);
+ r.assistToken, r.shareableActivityToken, r.initialCallerInfoAccessToken);
if (customIntent != null) {
activity.mIntent = customIntent;
diff --git a/core/java/android/app/ComponentCaller.java b/core/java/android/app/ComponentCaller.java
new file mode 100644
index 0000000..583408e
--- /dev/null
+++ b/core/java/android/app/ComponentCaller.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.FlaggedApi;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.Process;
+
+import androidx.annotation.NonNull;
+
+import java.util.Objects;
+
+/**
+ * Represents the app that launched the component. See below for the APIs available on the component
+ * caller.
+ *
+ * <p><b>Note</b>, that in {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} only
+ * {@link Activity} has access to {@link ComponentCaller} instances.
+ *
+ * @see Activity#getInitialCaller()
+ */
+@FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+public final class ComponentCaller {
+ private final IBinder mActivityToken;
+ private final IBinder mCallerToken;
+
+ public ComponentCaller(@NonNull IBinder activityToken, @Nullable IBinder callerToken) {
+ mActivityToken = activityToken;
+ mCallerToken = callerToken;
+ }
+
+ /**
+ * Returns the uid of this component caller.
+ *
+ * <p><b>Note</b>, in {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} only
+ * {@link Activity} has access to {@link ComponentCaller} instances.
+ * <p>
+ * <h3>Requirements for {@link Activity} callers</h3>
+ *
+ * <p>In order to receive the calling app's uid, at least one of the following has to be met:
+ * <ul>
+ * <li>The calling app must call {@link ActivityOptions#setShareIdentityEnabled(boolean)}
+ * with a value of {@code true} and launch this activity with the resulting
+ * {@code ActivityOptions}.
+ * <li>The launched activity has the same uid as the calling app.
+ * <li>The launched activity is running in a package that is signed with the same key used
+ * to sign the platform (typically only system packages such as Settings will meet this
+ * requirement).
+ * </ul>
+ * These are the same requirements for {@link #getPackage()}; if any of these are met, then
+ * these methods can be used to obtain the uid and package name of the calling app. If none are
+ * met, then {@link Process#INVALID_UID} is returned.
+ *
+ * <p>Note, even if the above conditions are not met, the calling app's identity may still be
+ * available from {@link Activity#getCallingPackage()} if this activity was started with
+ * {@code Activity#startActivityForResult} to allow validation of the result's recipient.
+ *
+ * @return the uid of the calling app or {@link Process#INVALID_UID} if the current component
+ * cannot access the identity of the calling app or the caller is invalid
+ *
+ * @see ActivityOptions#setShareIdentityEnabled(boolean)
+ * @see Activity#getLaunchedFromUid()
+ */
+ public int getUid() {
+ return ActivityClient.getInstance().getLaunchedFromUid(mActivityToken);
+ }
+
+ /**
+ * Returns the package name of this component caller.
+ *
+ * <p><b>Note</b>, in {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} only
+ * {@link Activity} has access to {@link ComponentCaller} instances.
+ * <p>
+ * <h3>Requirements for {@link Activity} callers</h3>
+ *
+ * <p>In order to receive the calling app's package name, at least one of the following has to
+ * be met:
+ * <ul>
+ * <li>The calling app must call {@link ActivityOptions#setShareIdentityEnabled(boolean)}
+ * with a value of {@code true} and launch this activity with the resulting
+ * {@code ActivityOptions}.
+ * <li>The launched activity has the same uid as the calling app.
+ * <li>The launched activity is running in a package that is signed with the same key used
+ * to sign the platform (typically only system packages such as Settings will meet this
+ * meet this requirement).
+ * </ul>
+ * These are the same requirements for {@link #getUid()}; if any of these are met, then these
+ * methods can be used to obtain the uid and package name of the calling app. If none are met,
+ * then {@code null} is returned.
+ *
+ * <p>Note, even if the above conditions are not met, the calling app's identity may still be
+ * available from {@link Activity#getCallingPackage()} if this activity was started with
+ * {@code Activity#startActivityForResult} to allow validation of the result's recipient.
+ *
+ * @return the package name of the calling app or null if the current component cannot access
+ * the identity of the calling app or the caller is invalid
+ *
+ * @see ActivityOptions#setShareIdentityEnabled(boolean)
+ * @see Activity#getLaunchedFromPackage()
+ */
+ @Nullable
+ public String getPackage() {
+ return ActivityClient.getInstance().getLaunchedFromPackage(mActivityToken);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (obj == null || !(obj instanceof ComponentCaller other)) {
+ return false;
+ }
+ return this.mActivityToken == other.mActivityToken
+ && this.mCallerToken == other.mCallerToken;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + Objects.hashCode(mActivityToken);
+ result = 31 * result + Objects.hashCode(mCallerToken);
+ return result;
+ }
+}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 68512b8..454d605 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1423,8 +1423,8 @@
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration(), null /* referrer */, null /* voiceInteractor */,
- null /* window */, null /* activityCallback */, null /*assistToken*/,
- null /*shareableActivityToken*/);
+ null /* window */, null /* activityCallback */, null /* assistToken */,
+ null /* shareableActivityToken */, null /* initialCallerInfoAccessToken */);
return activity;
}
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 4d53701..95f5ad0 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -80,6 +80,7 @@
private IBinder mShareableActivityToken;
private boolean mLaunchedFromBubble;
private IBinder mTaskFragmentToken;
+ private IBinder mInitialCallerInfoAccessToken;
/**
* It is only non-null if the process is the first time to launch activity. It is only an
* optimization for quick look up of the interface so the field is ignored for comparison.
@@ -106,7 +107,7 @@
mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mSceneTransitionInfo, mIsForward,
mProfilerInfo, client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
- mTaskFragmentToken);
+ mTaskFragmentToken, mInitialCallerInfoAccessToken);
client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -140,7 +141,7 @@
boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken,
@Nullable IActivityClientController activityClientController,
@NonNull IBinder shareableActivityToken, boolean launchedFromBubble,
- @Nullable IBinder taskFragmentToken) {
+ @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken) {
LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
if (instance == null) {
instance = new LaunchActivityItem();
@@ -155,7 +156,7 @@
sceneTransitionInfo, isForward,
profilerInfo != null ? new ProfilerInfo(profilerInfo) : null,
assistToken, activityClientController, shareableActivityToken,
- launchedFromBubble, taskFragmentToken);
+ launchedFromBubble, taskFragmentToken, initialCallerInfoAccessToken);
return instance;
}
@@ -170,7 +171,7 @@
@Override
public void recycle() {
setValues(this, null, null, 0, null, null, null, 0, null, null, 0, null, null, null, null,
- null, false, null, null, null, null, false, null);
+ null, false, null, null, null, null, false, null, null);
ObjectPool.recycle(this);
}
@@ -201,6 +202,7 @@
dest.writeStrongBinder(mShareableActivityToken);
dest.writeBoolean(mLaunchedFromBubble);
dest.writeStrongBinder(mTaskFragmentToken);
+ dest.writeStrongBinder(mInitialCallerInfoAccessToken);
}
/** Read from Parcel. */
@@ -220,6 +222,7 @@
IActivityClientController.Stub.asInterface(in.readStrongBinder()),
in.readStrongBinder(),
in.readBoolean(),
+ in.readStrongBinder(),
in.readStrongBinder());
}
@@ -259,7 +262,9 @@
&& Objects.equals(mProfilerInfo, other.mProfilerInfo)
&& Objects.equals(mAssistToken, other.mAssistToken)
&& Objects.equals(mShareableActivityToken, other.mShareableActivityToken)
- && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken);
+ && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken)
+ && Objects.equals(mInitialCallerInfoAccessToken,
+ other.mInitialCallerInfoAccessToken);
}
@Override
@@ -283,6 +288,7 @@
result = 31 * result + Objects.hashCode(mAssistToken);
result = 31 * result + Objects.hashCode(mShareableActivityToken);
result = 31 * result + Objects.hashCode(mTaskFragmentToken);
+ result = 31 * result + Objects.hashCode(mInitialCallerInfoAccessToken);
return result;
}
@@ -345,7 +351,7 @@
@Nullable ProfilerInfo profilerInfo, @Nullable IBinder assistToken,
@Nullable IActivityClientController activityClientController,
@Nullable IBinder shareableActivityToken, boolean launchedFromBubble,
- @Nullable IBinder taskFragmentToken) {
+ @Nullable IBinder taskFragmentToken, @Nullable IBinder initialCallerInfoAccessToken) {
instance.mActivityToken = activityToken;
instance.mIntent = intent;
instance.mIdent = ident;
@@ -368,5 +374,6 @@
instance.mShareableActivityToken = shareableActivityToken;
instance.mLaunchedFromBubble = launchedFromBubble;
instance.mTaskFragmentToken = taskFragmentToken;
+ instance.mInitialCallerInfoAccessToken = initialCallerInfoAccessToken;
}
}
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 4b27953..7ded747 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -44,6 +44,20 @@
}
flag {
+ name: "start_user_before_scheduled_alarms"
+ namespace: "multiuser"
+ description: "Persist list of users with alarms scheduled and wakeup stopped users before alarms are due"
+ bug: "314907186"
+}
+
+flag {
+ name: "add_ui_for_sounds_from_background_users"
+ namespace: "multiuser"
+ description: "Allow foreground user to dismiss sounds that are coming from background users"
+ bug: "314907186"
+}
+
+flag {
name: "enable_biometrics_to_unlock_private_space"
namespace: "profile_experiences"
description: "Add support to unlock the private space using biometrics"
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 35ae3c9..5dfeac7 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -693,7 +693,7 @@
* Begins a transaction in DEFERRED mode, with the android-specific constraint that the
* transaction is read-only. The database may not be modified inside a read-only transaction.
* <p>
- * Read-only transactions may run concurrently with other read-only transactions, and if they
+ * Read-only transactions may run concurrently with other read-only transactions, and if the
* database is in WAL mode, they may also run concurrently with IMMEDIATE or EXCLUSIVE
* transactions.
* <p>
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 71698e4..281ee50 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1256,7 +1256,9 @@
private void updateEditorToolTypeInternal(int toolType) {
if (Flags.useHandwritingListenerForTooltype()) {
mLastUsedToolType = toolType;
- mInputEditorInfo.setInitialToolType(toolType);
+ if (mInputEditorInfo != null) {
+ mInputEditorInfo.setInitialToolType(toolType);
+ }
}
onUpdateEditorToolType(toolType);
}
diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java
index e6bfcd7..224b10d 100644
--- a/core/java/android/os/PerformanceHintManager.java
+++ b/core/java/android/os/PerformanceHintManager.java
@@ -313,25 +313,33 @@
* close to the target duration.
*
* @param workDuration the work duration of each component.
- * @throws IllegalArgumentException if work period start timestamp is not positive, or
- * actual total duration is not positive, or actual CPU duration is not positive,
- * or actual GPU duration is negative.
+ * @throws IllegalArgumentException if
+ * the work period start timestamp or the total duration are less than or equal to zero,
+ * if either the actual CPU duration or actual GPU duration is less than zero,
+ * or if both the CPU and GPU durations are zero.
*/
@FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION)
public void reportActualWorkDuration(@NonNull WorkDuration workDuration) {
if (workDuration.mWorkPeriodStartTimestampNanos <= 0) {
throw new IllegalArgumentException(
- "the work period start timestamp should be positive.");
+ "the work period start timestamp should be greater than zero.");
}
if (workDuration.mActualTotalDurationNanos <= 0) {
- throw new IllegalArgumentException("the actual total duration should be positive.");
+ throw new IllegalArgumentException(
+ "the actual total duration should be greater than zero.");
}
- if (workDuration.mActualCpuDurationNanos <= 0) {
- throw new IllegalArgumentException("the actual CPU duration should be positive.");
+ if (workDuration.mActualCpuDurationNanos < 0) {
+ throw new IllegalArgumentException(
+ "the actual CPU duration should be greater than or equal to zero.");
}
if (workDuration.mActualGpuDurationNanos < 0) {
throw new IllegalArgumentException(
- "the actual GPU duration should be non negative.");
+ "the actual GPU duration should be greater than or equal to zero.");
+ }
+ if (workDuration.mActualCpuDurationNanos + workDuration.mActualGpuDurationNanos <= 0) {
+ throw new IllegalArgumentException(
+ "either the actual CPU duration or the actual GPU duration should be greater"
+ + "than zero.");
}
nativeReportActualWorkDuration(mNativeSessionPtr,
workDuration.mWorkPeriodStartTimestampNanos,
diff --git a/core/java/android/os/WorkDuration.java b/core/java/android/os/WorkDuration.java
index 2ebcd83..5a54e90 100644
--- a/core/java/android/os/WorkDuration.java
+++ b/core/java/android/os/WorkDuration.java
@@ -83,7 +83,7 @@
public void setWorkPeriodStartTimestampNanos(long workPeriodStartTimestampNanos) {
if (workPeriodStartTimestampNanos <= 0) {
throw new IllegalArgumentException(
- "the work period start timestamp should be positive.");
+ "the work period start timestamp should be greater than zero.");
}
mWorkPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
}
@@ -95,7 +95,8 @@
*/
public void setActualTotalDurationNanos(long actualTotalDurationNanos) {
if (actualTotalDurationNanos <= 0) {
- throw new IllegalArgumentException("the actual total duration should be positive.");
+ throw new IllegalArgumentException(
+ "the actual total duration should be greater than zero.");
}
mActualTotalDurationNanos = actualTotalDurationNanos;
}
@@ -106,8 +107,9 @@
* All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public void setActualCpuDurationNanos(long actualCpuDurationNanos) {
- if (actualCpuDurationNanos <= 0) {
- throw new IllegalArgumentException("the actual CPU duration should be positive.");
+ if (actualCpuDurationNanos < 0) {
+ throw new IllegalArgumentException(
+ "the actual CPU duration should be greater than or equal to zero.");
}
mActualCpuDurationNanos = actualCpuDurationNanos;
}
@@ -119,7 +121,8 @@
*/
public void setActualGpuDurationNanos(long actualGpuDurationNanos) {
if (actualGpuDurationNanos < 0) {
- throw new IllegalArgumentException("the actual GPU duration should be non negative.");
+ throw new IllegalArgumentException(
+ "the actual GPU duration should be greater than or equal to zero.");
}
mActualGpuDurationNanos = actualGpuDurationNanos;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 76fda06..ef2d5eb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -18161,6 +18161,16 @@
"show_notification_channel_warnings";
/**
+ * Whether to disable app and notification screen share protections.
+ *
+ * The value 1 - enable, 0 - disable
+ * @hide
+ */
+ @Readable
+ public static final String DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS =
+ "disable_screen_share_protections_for_apps_and_notifications";
+
+ /**
* Whether cell is enabled/disabled
* @hide
*/
diff --git a/core/java/android/tracing/transition/TransitionDataSource.java b/core/java/android/tracing/transition/TransitionDataSource.java
index 82559da..744f446 100644
--- a/core/java/android/tracing/transition/TransitionDataSource.java
+++ b/core/java/android/tracing/transition/TransitionDataSource.java
@@ -16,7 +16,6 @@
package android.tracing.transition;
-import android.tracing.perfetto.CreateTlsStateArgs;
import android.tracing.perfetto.DataSource;
import android.tracing.perfetto.DataSourceInstance;
import android.tracing.perfetto.FlushCallbackArguments;
@@ -24,23 +23,17 @@
import android.tracing.perfetto.StopCallbackArguments;
import android.util.proto.ProtoInputStream;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
/**
* @hide
*/
public class TransitionDataSource
- extends DataSource<DataSourceInstance, TransitionDataSource.TlsState, Void> {
+ extends DataSource<DataSourceInstance, Void, Void> {
public static String DATA_SOURCE_NAME = "com.android.wm.shell.transition";
private final Runnable mOnStartStaticCallback;
private final Runnable mOnFlushStaticCallback;
private final Runnable mOnStopStaticCallback;
- private final ConcurrentHashMap<Integer, ConcurrentHashMap<String, Integer>> mHandlerMappings =
- new ConcurrentHashMap<>();
-
public TransitionDataSource(Runnable onStart, Runnable onFlush, Runnable onStop) {
super(DATA_SOURCE_NAME);
this.mOnStartStaticCallback = onStart;
@@ -49,20 +42,6 @@
}
@Override
- protected TlsState createTlsState(CreateTlsStateArgs<DataSourceInstance> args) {
- return new TlsState(args.getDataSourceInstanceLocked().getInstanceIndex());
- }
-
- public class TlsState {
- public final Map<String, Integer> handlerMapping;
-
- public TlsState(int instanceIndex) {
- handlerMapping = mHandlerMappings
- .computeIfAbsent(instanceIndex, index -> new ConcurrentHashMap<>());
- }
- }
-
- @Override
public DataSourceInstance createInstance(ProtoInputStream configStream, int instanceIndex) {
return new DataSourceInstance(this, instanceIndex) {
@Override
@@ -78,7 +57,6 @@
@Override
protected void onStop(StopCallbackArguments args) {
mOnStopStaticCallback.run();
- mHandlerMappings.remove(instanceIndex);
}
};
}
diff --git a/core/java/android/view/accessibility/MagnificationAnimationCallback.java b/core/java/android/view/accessibility/MagnificationAnimationCallback.java
index 72518db..1755497 100644
--- a/core/java/android/view/accessibility/MagnificationAnimationCallback.java
+++ b/core/java/android/view/accessibility/MagnificationAnimationCallback.java
@@ -16,6 +16,8 @@
package android.view.accessibility;
+import android.view.MagnificationSpec;
+
/**
* A callback for magnification animation result.
* @hide
@@ -31,4 +33,16 @@
* change. Otherwise {@code false}
*/
void onResult(boolean success);
+
+ /**
+ * Called when the animation is finished or interrupted during animating.
+ *
+ * @param success {@code true} if animating successfully with given spec or the spec did not
+ * change. Otherwise {@code false}
+ * @param lastSpecSent the last spec that was sent to WindowManager for animation, in case you
+ * need to update the local copy
+ */
+ default void onResult(boolean success, MagnificationSpec lastSpecSent) {
+ onResult(success);
+ }
}
\ No newline at end of file
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 323f7b6..b5fbb22 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -73,7 +73,7 @@
uint32_t mNextPublishedSeq;
const std::string getInputChannelName() {
- return mInputPublisher.getChannel()->getName();
+ return mInputPublisher.getChannel().getName();
}
int handleEvent(int receiveFd, int events, void* data) override;
@@ -102,7 +102,7 @@
}
status_t NativeInputEventSender::initialize() {
- const int receiveFd = mInputPublisher.getChannel()->getFd();
+ const int receiveFd = mInputPublisher.getChannel().getFd();
mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL);
return OK;
}
@@ -112,7 +112,7 @@
LOG(DEBUG) << "channel '" << getInputChannelName() << "' ~ Disposing input event sender.";
}
- mMessageQueue->getLooper()->removeFd(mInputPublisher.getChannel()->getFd());
+ mMessageQueue->getLooper()->removeFd(mInputPublisher.getChannel().getFd());
}
status_t NativeInputEventSender::sendKeyEvent(uint32_t seq, const KeyEvent* event) {
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d3f3af7..2861858 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -723,6 +723,7 @@
// encoded as a key=value list separated by commas.
optional SettingProto smart_suggestions_in_notifications_flags = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto bubbles = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto disable_screen_share_protections_for_apps_and_notifications = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Notification notification = 82;
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index 296c451..262f167 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertThrows;
+import android.Manifest;
import android.app.compat.CompatChanges;
import android.graphics.Bitmap;
import android.hardware.broadcastradio.ConfigFlag;
@@ -57,6 +58,8 @@
import android.util.ArrayMap;
import android.util.ArraySet;
+import androidx.test.platform.app.InstrumentationRegistry;
+
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase;
import com.android.server.broadcastradio.RadioServiceUserController;
@@ -171,6 +174,10 @@
@Before
public void setup() throws Exception {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+
doReturn(true).when(() -> CompatChanges.isChangeEnabled(
eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt()));
doReturn(USER_ID_1).when(mUserHandleMock).getIdentifier();
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index a796a0f..c6447be 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -123,6 +123,7 @@
final IBinder shareableActivityToken = new Binder();
final int deviceId = 3;
final IBinder taskFragmentToken = new Binder();
+ final IBinder initialCallerInfoAccessToken = new Binder();
testRecycle(() -> new LaunchActivityItemBuilder(
activityToken, intent, activityInfo)
@@ -140,6 +141,7 @@
.setShareableActivityToken(shareableActivityToken)
.setTaskFragmentToken(taskFragmentToken)
.setDeviceId(deviceId)
+ .setInitialCallerInfoAccessToken(initialCallerInfoAccessToken)
.build());
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 3823033..d641659 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -132,6 +132,8 @@
private boolean mLaunchedFromBubble;
@Nullable
private IBinder mTaskFragmentToken;
+ @Nullable
+ private IBinder mInitialCallerInfoAccessToken;
LaunchActivityItemBuilder(@NonNull IBinder activityToken, @NonNull Intent intent,
@NonNull ActivityInfo info) {
@@ -251,13 +253,21 @@
}
@NonNull
+ LaunchActivityItemBuilder setInitialCallerInfoAccessToken(
+ @Nullable IBinder initialCallerInfoAccessToken) {
+ mInitialCallerInfoAccessToken = initialCallerInfoAccessToken;
+ return this;
+ }
+
+ @NonNull
LaunchActivityItem build() {
return LaunchActivityItem.obtain(mActivityToken, mIntent, mIdent, mInfo,
mCurConfig, mOverrideConfig, mDeviceId, mReferrer, mVoiceInteractor,
mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
mActivityOptions != null ? mActivityOptions.getSceneTransitionInfo() : null,
mIsForward, mProfilerInfo, mAssistToken, null /* activityClientController */,
- mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken);
+ mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken,
+ mInitialCallerInfoAccessToken);
}
}
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 952cdd9..508c6b2 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -189,6 +189,7 @@
.setAssistToken(new Binder())
.setShareableActivityToken(new Binder())
.setTaskFragmentToken(new Binder())
+ .setInitialCallerInfoAccessToken(new Binder())
.build();
writeAndPrepareForReading(item);
diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
index a28bb69..2bd5631 100644
--- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
@@ -219,6 +219,22 @@
workDuration.setActualGpuDurationNanos(6);
s.reportActualWorkDuration(workDuration);
}
+ {
+ WorkDuration workDuration = new WorkDuration();
+ workDuration.setWorkPeriodStartTimestampNanos(1);
+ workDuration.setActualTotalDurationNanos(14);
+ workDuration.setActualCpuDurationNanos(0);
+ workDuration.setActualGpuDurationNanos(6);
+ s.reportActualWorkDuration(workDuration);
+ }
+ {
+ WorkDuration workDuration = new WorkDuration();
+ workDuration.setWorkPeriodStartTimestampNanos(1);
+ workDuration.setActualTotalDurationNanos(14);
+ workDuration.setActualCpuDurationNanos(7);
+ workDuration.setActualGpuDurationNanos(0);
+ s.reportActualWorkDuration(workDuration);
+ }
}
@Test
@@ -242,7 +258,7 @@
s.reportActualWorkDuration(new WorkDuration(1, 12, -1, 6, 1));
});
assertThrows(IllegalArgumentException.class, () -> {
- s.reportActualWorkDuration(new WorkDuration(1, 12, 0, 6, 1));
+ s.reportActualWorkDuration(new WorkDuration(1, 12, 0, 0, 1));
});
assertThrows(IllegalArgumentException.class, () -> {
s.reportActualWorkDuration(new WorkDuration(1, 12, 8, -1, 1));
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 3e0e36d..39cb616 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -353,7 +353,8 @@
null /* pendingResults */, null /* pendingNewIntents */,
null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
mThread /* client */, null /* asssitToken */, null /* shareableActivityToken */,
- false /* launchedFromBubble */, null /* taskfragmentToken */);
+ false /* launchedFromBubble */, null /* taskfragmentToken */,
+ null /* initialCallerInfoAccessToken */);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 50a58da..a2a2914 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -19,6 +19,7 @@
import static android.os.AsyncTask.Status.FINISHED;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
import android.annotation.DimenRes;
import android.annotation.Hide;
@@ -47,6 +48,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
@@ -466,6 +468,7 @@
* Call when all the views should be removed/cleaned up.
*/
public void cleanupViews() {
+ ProtoLog.d(WM_SHELL_BUBBLES, "Bubble#cleanupViews=%s", getKey());
cleanupViews(true);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index a43a951..621c453 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -23,7 +23,6 @@
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_BLOCKED;
@@ -435,6 +434,9 @@
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
for (Bubble b : mBubbleData.getBubbles()) {
if (task.taskId == b.getTaskId()) {
+ ProtoLog.d(WM_SHELL_BUBBLES,
+ "onActivityRestartAttempt - taskId=%d selecting matching bubble=%s",
+ task.taskId, b.getKey());
mBubbleData.setSelectedBubble(b);
mBubbleData.setExpanded(true);
return;
@@ -442,6 +444,9 @@
}
for (Bubble b : mBubbleData.getOverflowBubbles()) {
if (task.taskId == b.getTaskId()) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onActivityRestartAttempt - taskId=%d "
+ + "selecting matching overflow bubble=%s",
+ task.taskId, b.getKey());
promoteBubbleFromOverflow(b);
mBubbleData.setExpanded(true);
return;
@@ -581,10 +586,15 @@
// Hide the stack temporarily if the status bar has been made invisible, and the stack
// is collapsed. An expanded stack should remain visible until collapsed.
mStackView.setTemporarilyInvisible(!visible && !isStackExpanded());
+ ProtoLog.d(WM_SHELL_BUBBLES, "onStatusBarVisibilityChanged=%b stackExpanded=%b",
+ visible, isStackExpanded());
}
}
private void onZenStateChanged() {
+ if (hasBubbles()) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onZenStateChanged");
+ }
for (Bubble b : mBubbleData.getBubbles()) {
b.setShowDot(b.showInShade());
}
@@ -593,9 +603,10 @@
@VisibleForTesting
public void onStatusBarStateChanged(boolean isShade) {
boolean didChange = mIsStatusBarShade != isShade;
- if (DEBUG_BUBBLE_CONTROLLER) {
- Log.d(TAG, "onStatusBarStateChanged isShade=" + isShade + " didChange=" + didChange);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "onStatusBarStateChanged "
+ + "isShade=%b didChange=%b mNotifEntryToExpandOnShadeUnlock=%s",
+ isShade, didChange, (mNotifEntryToExpandOnShadeUnlock != null
+ ? mNotifEntryToExpandOnShadeUnlock.getKey() : "null"));
mIsStatusBarShade = isShade;
if (!mIsStatusBarShade && didChange) {
// Only collapse stack on change
@@ -611,6 +622,8 @@
@VisibleForTesting
public void onBubbleMetadataFlagChanged(Bubble bubble) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onBubbleMetadataFlagChanged=%s flags=%d",
+ bubble.getKey(), bubble.getFlags());
// Make sure NoMan knows suppression state so that anyone querying it can tell.
try {
mBarService.onBubbleMetadataFlagChanged(bubble.getKey(), bubble.getFlags());
@@ -623,6 +636,8 @@
/** Called when the current user changes. */
@VisibleForTesting
public void onUserChanged(int newUserId) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onUserChanged currentUser=%d newUser=%d",
+ mCurrentUserId, newUserId);
saveBubbles(mCurrentUserId);
mCurrentUserId = newUserId;
@@ -825,6 +840,7 @@
*/
void updateWindowFlagsForBackpress(boolean interceptBack) {
if (mAddedToWindowManager) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "updateFlagsForBackPress interceptBack=%b", interceptBack);
mWmLayoutParams.flags = interceptBack
? 0
: WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -1014,8 +1030,9 @@
}
private void onNotificationPanelExpandedChanged(boolean expanded) {
- ProtoLog.d(WM_SHELL_BUBBLES, "onNotificationPanelExpandedChanged: expanded=%b", expanded);
if (mStackView != null && mStackView.isExpanded()) {
+ ProtoLog.d(WM_SHELL_BUBBLES,
+ "onNotificationPanelExpandedChanged expanded=%b", expanded);
if (expanded) {
mStackView.stopMonitoringSwipeUpGesture();
} else {
@@ -1096,6 +1113,7 @@
/** Promote the provided bubble from the overflow view. */
public void promoteBubbleFromOverflow(Bubble bubble) {
mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
+ ProtoLog.d(WM_SHELL_BUBBLES, "promoteBubbleFromOverflow=%s", bubble.getKey());
bubble.setInflateSynchronously(mInflateSynchronously);
bubble.setShouldAutoExpand(true);
bubble.markAsAccessedAt(System.currentTimeMillis());
@@ -1211,11 +1229,8 @@
// Skip update, but store it in user bubbles so it gets restored after user switch
mSavedUserBubbleData.get(bubbleUserId, new UserBubbleData()).add(notif.getKey(),
true /* shownInShade */);
- if (DEBUG_BUBBLE_CONTROLLER) {
- Log.d(TAG,
- "Ignore update to bubble for not active user. Bubble userId=" + bubbleUserId
- + " current userId=" + mCurrentUserId);
- }
+ Log.w(TAG, "updateBubble, ignore update for non-active user=" + bubbleUserId
+ + " currentUser=" + mCurrentUserId);
}
}
@@ -1252,7 +1267,9 @@
}
String appBubbleKey = Bubble.getAppBubbleKeyForApp(intent.getPackage(), user);
- Log.i(TAG, "showOrHideAppBubble, with key: " + appBubbleKey);
+ Log.i(TAG, "showOrHideAppBubble, key= " + appBubbleKey + " stackVisibility= "
+ + (mStackView != null ? mStackView.getVisibility() : " null ")
+ + " statusBarShade=" + mIsStatusBarShade);
PackageManager packageManager = getPackageManagerForUser(mContext, user.getIdentifier());
if (!isResizableActivity(intent, packageManager, appBubbleKey)) return;
@@ -1769,18 +1786,19 @@
@Override
public void applyUpdate(BubbleData.Update update) {
- if (DEBUG_BUBBLE_CONTROLLER) {
- Log.d(TAG, "applyUpdate:" + " bubbleAdded=" + (update.addedBubble != null)
- + " bubbleRemoved="
- + (update.removedBubbles != null && update.removedBubbles.size() > 0)
- + " bubbleUpdated=" + (update.updatedBubble != null)
- + " orderChanged=" + update.orderChanged
- + " expandedChanged=" + update.expandedChanged
- + " selectionChanged=" + update.selectionChanged
- + " suppressed=" + (update.suppressedBubble != null)
- + " unsuppressed=" + (update.unsuppressedBubble != null)
- + " shouldShowEducation=" + update.shouldShowEducation);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "mBubbleDataListener#applyUpdate:"
+ + " added=%s removed=%b updated=%s orderChanged=%b expansionChanged=%b"
+ + " expanded=%b selectionChanged=%b selected=%s"
+ + " suppressed=%s unsupressed=%s shouldShowEducation=%b",
+ update.addedBubble != null ? update.addedBubble.getKey() : "null",
+ update.removedBubbles.isEmpty(),
+ update.updatedBubble != null ? update.updatedBubble.getKey() : "null",
+ update.orderChanged, update.expandedChanged, update.expanded,
+ update.selectionChanged,
+ update.selectedBubble != null ? update.selectedBubble.getKey() : "null",
+ update.suppressedBubble != null ? update.suppressedBubble.getKey() : "null",
+ update.unsuppressedBubble != null ? update.unsuppressedBubble.getKey() : "null",
+ update.shouldShowEducation);
ensureBubbleViewsAndWindowCreated();
@@ -1974,7 +1992,8 @@
if (mStackView == null && mLayerView == null) {
return;
}
-
+ ProtoLog.v(WM_SHELL_BUBBLES, "updateBubbleViews mIsStatusBarShade=%s hasBubbles=%s",
+ mIsStatusBarShade, hasBubbles());
if (!mIsStatusBarShade) {
// Bubbles don't appear when the device is locked.
if (mStackView != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index dbfa260..6d3f0c3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -16,10 +16,9 @@
package com.android.wm.shell.bubbles;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
-import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
import android.annotation.NonNull;
import android.app.PendingIntent;
@@ -36,6 +35,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.R;
@@ -333,9 +333,6 @@
}
public void setExpanded(boolean expanded) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "setExpanded: " + expanded);
- }
setExpandedInternal(expanded);
dispatchPendingChanges();
}
@@ -347,9 +344,8 @@
* updated to have the correct state.
*/
public void setSelectedBubbleFromLauncher(BubbleViewProvider bubble) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "setSelectedBubbleFromLauncher: " + bubble);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "setSelectedBubbleFromLauncher=%s",
+ (bubble != null ? bubble.getKey() : "null"));
mExpanded = true;
if (Objects.equals(bubble, mSelectedBubble)) {
return;
@@ -370,9 +366,6 @@
}
public void setSelectedBubble(BubbleViewProvider bubble) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "setSelectedBubble: " + bubble);
- }
setSelectedBubbleInternal(bubble);
dispatchPendingChanges();
}
@@ -430,12 +423,13 @@
* BubbleBarLayerView, BubbleIconFactory, boolean)
*/
void notificationEntryUpdated(Bubble bubble, boolean suppressFlyout, boolean showInShade) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "notificationEntryUpdated: " + bubble);
- }
mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here
Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
suppressFlyout |= !bubble.isTextChanged();
+ ProtoLog.d(WM_SHELL_BUBBLES,
+ "notifEntryUpdated=%s prevBubble=%b suppressFlyout=%b showInShade=%b autoExpand=%b",
+ bubble.getKey(), (prevBubble != null), suppressFlyout, showInShade,
+ bubble.shouldAutoExpand());
if (prevBubble == null) {
// Create a new bubble
@@ -483,9 +477,6 @@
* Dismisses the bubble with the matching key, if it exists.
*/
public void dismissBubbleWithKey(String key, @DismissReason int reason) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "notificationEntryRemoved: key=" + key + " reason=" + reason);
- }
doRemove(key, reason);
dispatchPendingChanges();
}
@@ -603,9 +594,7 @@
}
private void doAdd(Bubble bubble) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "doAdd: " + bubble);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "doAdd=%s", bubble.getKey());
mBubbles.add(0, bubble);
mStateChange.addedBubble = bubble;
// Adding the first bubble doesn't change the order
@@ -634,9 +623,7 @@
}
private void doUpdate(Bubble bubble, boolean reorder) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "doUpdate: " + bubble);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "BubbleData - doUpdate=%s", bubble.getKey());
mStateChange.updatedBubble = bubble;
if (!isExpanded() && reorder) {
int prevPos = mBubbles.indexOf(bubble);
@@ -663,9 +650,6 @@
}
private void doRemove(String key, @DismissReason int reason) {
- if (DEBUG_BUBBLE_DATA || (key != null && key.contains(KEY_APP_BUBBLE))) {
- Log.d(TAG, "doRemove: " + key + " reason: " + reason);
- }
// If it was pending remove it
if (mPendingBubbles.containsKey(key)) {
mPendingBubbles.remove(key);
@@ -686,9 +670,7 @@
&& shouldRemoveHiddenBubble) {
Bubble b = getOverflowBubbleWithKey(key);
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "Cancel overflow bubble: " + b);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "doRemove - cancel overflow bubble=%s", key);
if (b != null) {
b.stopInflation();
}
@@ -699,9 +681,7 @@
}
if (hasSuppressedBubbleWithKey(key) && shouldRemoveHiddenBubble) {
Bubble b = getSuppressedBubbleWithKey(key);
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "Cancel suppressed bubble: " + b);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "doRemove - cancel suppressed bubble=%s", key);
if (b != null) {
mSuppressedBubbles.remove(b.getLocusId());
b.stopInflation();
@@ -711,6 +691,7 @@
return;
}
Bubble bubbleToRemove = mBubbles.get(indexToRemove);
+ ProtoLog.d(WM_SHELL_BUBBLES, "doRemove=%s", bubbleToRemove.getKey());
bubbleToRemove.stopInflation();
overflowBubble(reason, bubbleToRemove);
@@ -744,17 +725,12 @@
}
// Move selection to the new bubble at the same position.
int newIndex = Math.min(indexOfSelected, mBubbles.size() - 1);
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "setNewSelectedIndex: " + indexOfSelected);
- }
BubbleViewProvider newSelected = mBubbles.get(newIndex);
setSelectedBubbleInternal(newSelected);
}
private void doSuppress(Bubble bubble) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "doSuppressed: " + bubble);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "doSuppress=%s", bubble.getKey());
mStateChange.suppressedBubble = bubble;
bubble.setSuppressBubble(true);
@@ -777,9 +753,7 @@
}
private void doUnsuppress(Bubble bubble) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "doUnsuppressed: " + bubble);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "doUnsuppress=%s", bubble.getKey());
bubble.setSuppressBubble(false);
mStateChange.unsuppressedBubble = bubble;
mBubbles.add(bubble);
@@ -801,9 +775,7 @@
|| reason == Bubbles.DISMISS_RELOAD_FROM_DISK)) {
return;
}
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "Overflowing: " + bubble);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "overflowBubble=%s", bubble.getKey());
mLogger.logOverflowAdd(bubble, reason);
mOverflowBubbles.remove(bubble);
mOverflowBubbles.add(0, bubble);
@@ -812,9 +784,7 @@
if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
// Remove oldest bubble.
Bubble oldest = mOverflowBubbles.get(mOverflowBubbles.size() - 1);
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "Overflow full. Remove: " + oldest);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "overflow full, remove=%s", oldest.getKey());
mStateChange.bubbleRemoved(oldest, Bubbles.DISMISS_OVERFLOW_MAX_REACHED);
mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_MAX_REACHED);
mOverflowBubbles.remove(oldest);
@@ -823,9 +793,7 @@
}
public void dismissAll(@DismissReason int reason) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "dismissAll: reason=" + reason);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "dismissAll reason=%d", reason);
if (mBubbles.isEmpty() && mSuppressedBubbles.isEmpty()) {
return;
}
@@ -851,9 +819,10 @@
* @param visible whether the task with the locusId is visible or not.
*/
public void onLocusVisibilityChanged(int taskId, LocusId locusId, boolean visible) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "onLocusVisibilityChanged: " + locusId + " visible=" + visible);
- }
+ if (locusId == null) return;
+
+ ProtoLog.d(WM_SHELL_BUBBLES, "onLocusVisibilityChanged=%s visible=%b taskId=%d",
+ locusId.getId(), visible, taskId);
Bubble matchingBubble = getBubbleInStackWithLocusId(locusId);
// Don't add the locus if it's from a bubble'd activity, we only suppress for non-bubbled.
@@ -910,9 +879,8 @@
* @param bubble the new selected bubble
*/
private void setSelectedBubbleInternal(@Nullable BubbleViewProvider bubble) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "setSelectedBubbleInternal: " + bubble);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "setSelectedBubbleInternal=%s",
+ (bubble != null ? bubble.getKey() : "null"));
if (Objects.equals(bubble, mSelectedBubble)) {
return;
}
@@ -969,12 +937,10 @@
* @param shouldExpand the new requested state
*/
private void setExpandedInternal(boolean shouldExpand) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "setExpandedInternal: shouldExpand=" + shouldExpand);
- }
if (mExpanded == shouldExpand) {
return;
}
+ ProtoLog.d(WM_SHELL_BUBBLES, "setExpandedInternal=%b", shouldExpand);
if (shouldExpand) {
if (mBubbles.isEmpty() && !mShowingOverflow) {
Log.e(TAG, "Attempt to expand stack when empty!");
@@ -1026,9 +992,6 @@
* @return true if the position of any bubbles changed as a result
*/
private boolean repackAll() {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "repackAll()");
- }
if (mBubbles.isEmpty()) {
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
index f56b171..f1a68e2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
@@ -37,17 +37,7 @@
// Default log tag for the Bubbles package.
public static final String TAG_BUBBLES = "Bubbles";
-
- static final boolean DEBUG_BUBBLE_CONTROLLER = false;
- static final boolean DEBUG_BUBBLE_DATA = false;
- static final boolean DEBUG_BUBBLE_STACK_VIEW = false;
- static final boolean DEBUG_BUBBLE_EXPANDED_VIEW = false;
- static final boolean DEBUG_EXPERIMENTS = true;
- static final boolean DEBUG_OVERFLOW = false;
public static final boolean DEBUG_USER_EDUCATION = false;
- static final boolean DEBUG_POSITIONER = false;
- public static final boolean DEBUG_COLLAPSE_ANIMATOR = false;
- public static boolean DEBUG_EXPANDED_VIEW_DRAGGING = false;
private static final boolean FORCE_SHOW_USER_EDUCATION = false;
private static final String FORCE_SHOW_USER_EDUCATION_SETTING =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index efc4d8b..088660e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -23,10 +23,10 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
@@ -67,6 +67,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.AlphaOptimizedButton;
import com.android.wm.shell.common.TriangleShape;
@@ -199,13 +200,9 @@
@Override
public void onInitialized() {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onInitialized: destroyed=" + mDestroyed
- + " initialized=" + mInitialized
- + " bubble=" + getBubbleKey());
- }
-
if (mDestroyed || mInitialized) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: destroyed=%b initialized=%b bubble=%s",
+ mDestroyed, mInitialized, getBubbleKey());
return;
}
@@ -216,10 +213,8 @@
// TODO: I notice inconsistencies in lifecycle
// Post to keep the lifecycle normal
post(() -> {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onInitialized: calling startActivity, bubble="
- + getBubbleKey());
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s",
+ getBubbleKey());
try {
Rect launchBounds = new Rect();
mTaskView.getBoundsOnScreen(launchBounds);
@@ -279,10 +274,8 @@
@Override
public void onTaskCreated(int taskId, ComponentName name) {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onTaskCreated: taskId=" + taskId
- + " bubble=" + getBubbleKey());
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "onTaskCreated: taskId=%d bubble=%s",
+ taskId, getBubbleKey());
// The taskId is saved to use for removeTask, preventing appearance in recent tasks.
mTaskId = taskId;
@@ -298,15 +291,15 @@
@Override
public void onTaskVisibilityChanged(int taskId, boolean visible) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onTaskVisibilityChanged=%b bubble=%s taskId=%d",
+ visible, getBubbleKey(), taskId);
setContentVisibility(visible);
}
@Override
public void onTaskRemovalStarted(int taskId) {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onTaskRemovalStarted: taskId=" + taskId
- + " bubble=" + getBubbleKey());
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "onTaskRemovalStarted: taskId=%d bubble=%s",
+ taskId, getBubbleKey());
if (mBubble != null) {
mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
}
@@ -644,9 +637,6 @@
super.onDetachedFromWindow();
mImeVisible = false;
mNeedsNewHeight = false;
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onDetachedFromWindow: bubble=" + getBubbleKey());
- }
}
/**
@@ -805,10 +795,6 @@
* and setting {@code false} actually means rendering the contents in transparent.
*/
public void setContentVisibility(boolean visibility) {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "setContentVisibility: visibility=" + visibility
- + " bubble=" + getBubbleKey());
- }
mIsContentVisible = visibility;
if (mTaskView != null && !mIsAnimating) {
mTaskView.setAlpha(visibility ? 1f : 0f);
@@ -867,9 +853,6 @@
* Sets the bubble used to populate this view.
*/
void update(Bubble bubble) {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "update: bubble=" + bubble);
- }
if (mStackView == null) {
Log.w(TAG, "Stack is null for bubble: " + bubble);
return;
@@ -958,11 +941,6 @@
}
mNeedsNewHeight = false;
}
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "updateHeight: bubble=" + getBubbleKey()
- + " height=" + height
- + " mNeedsNewHeight=" + mNeedsNewHeight);
- }
}
}
@@ -974,10 +952,6 @@
* waiting for layout.
*/
public void updateView(int[] containerLocationOnScreen) {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "updateView: bubble="
- + getBubbleKey());
- }
mExpandedViewContainerLocation = containerLocationOnScreen;
updateHeight();
if (mTaskView != null
@@ -1103,9 +1077,6 @@
/** Hide the task view. */
public void cleanUpExpandedState() {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "cleanUpExpandedState: bubble=" + getBubbleKey() + " task=" + mTaskId);
- }
if (mTaskView != null) {
mTaskView.setVisibility(GONE);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index 9655470..70cdc82 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -16,9 +16,9 @@
package com.android.wm.shell.bubbles;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_OVERFLOW;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
import android.annotation.NonNull;
import android.content.Context;
@@ -28,7 +28,6 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -43,6 +42,7 @@
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ContrastColorUtil;
import com.android.wm.shell.R;
@@ -245,9 +245,6 @@
Bubble toRemove = update.removedOverflowBubble;
if (toRemove != null) {
- if (DEBUG_OVERFLOW) {
- Log.d(TAG, "remove: " + toRemove);
- }
toRemove.cleanupViews();
final int indexToRemove = mOverflowBubbles.indexOf(toRemove);
mOverflowBubbles.remove(toRemove);
@@ -257,9 +254,6 @@
Bubble toAdd = update.addedOverflowBubble;
if (toAdd != null) {
final int indexToAdd = mOverflowBubbles.indexOf(toAdd);
- if (DEBUG_OVERFLOW) {
- Log.d(TAG, "add: " + toAdd + " prevIndex: " + indexToAdd);
- }
if (indexToAdd > 0) {
mOverflowBubbles.remove(toAdd);
mOverflowBubbles.add(0, toAdd);
@@ -272,10 +266,9 @@
updateEmptyStateVisibility();
- if (DEBUG_OVERFLOW) {
- Log.d(TAG, BubbleDebugConfig.formatBubblesString(
- mController.getOverflowBubbles(), null));
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "Apply overflow update, added=%s removed=%s",
+ (toAdd != null ? toAdd.getKey() : "null"),
+ (toRemove != null ? toRemove.getKey() : "null"));
}
};
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index d62c86c..c03b6f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -16,18 +16,20 @@
package com.android.wm.shell.bubbles;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
+
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.util.Log;
import android.view.Surface;
import android.view.WindowManager;
import androidx.annotation.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.R;
@@ -36,9 +38,6 @@
* placement and positioning calculations to refer to.
*/
public class BubblePositioner {
- private static final String TAG = BubbleDebugConfig.TAG_WITH_CLASS_NAME
- ? "BubblePositioner"
- : BubbleDebugConfig.TAG_BUBBLES;
/** The screen edge the bubble stack is pinned to */
public enum StackPinnedEdge {
@@ -110,16 +109,12 @@
*/
public void update(DeviceConfig deviceConfig) {
mDeviceConfig = deviceConfig;
-
- if (BubbleDebugConfig.DEBUG_POSITIONER) {
- Log.w(TAG, "update positioner:"
- + " rotation: " + mRotation
- + " insets: " + deviceConfig.getInsets()
- + " isLargeScreen: " + deviceConfig.isLargeScreen()
- + " isSmallTablet: " + deviceConfig.isSmallTablet()
- + " showingInBubbleBar: " + mShowingInBubbleBar
- + " bounds: " + deviceConfig.getWindowBounds());
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "update positioner: "
+ + "rotation=%d insets=%s largeScreen=%b "
+ + "smallTablet=%b isBubbleBar=%b bounds=%s",
+ mRotation, deviceConfig.getInsets(), deviceConfig.isLargeScreen(),
+ deviceConfig.isSmallTablet(), mShowingInBubbleBar,
+ deviceConfig.getWindowBounds());
updateInternal(mRotation, deviceConfig.getInsets(), deviceConfig.getWindowBounds());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 9facef3..c877d4a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -21,7 +21,6 @@
import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
@@ -1310,13 +1309,9 @@
final boolean seen = getPrefBoolean(ManageEducationView.PREF_MANAGED_EDUCATION);
final boolean shouldShow = (!seen || BubbleDebugConfig.forceShowUserEducation(mContext))
&& mExpandedBubble != null && mExpandedBubble.getExpandedView() != null;
- if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
- Log.d(TAG, "Show manage edu: " + shouldShow);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "Show manage edu=%b", shouldShow);
if (shouldShow && BubbleDebugConfig.neverShowUserEducation(mContext)) {
- if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
- Log.d(TAG, "Want to show manage edu, but it is forced hidden");
- }
+ Log.w(TAG, "Want to show manage edu, but it is forced hidden");
return false;
}
return shouldShow;
@@ -1360,13 +1355,9 @@
}
final boolean seen = getPrefBoolean(StackEducationView.PREF_STACK_EDUCATION);
final boolean shouldShow = !seen || BubbleDebugConfig.forceShowUserEducation(mContext);
- if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
- Log.d(TAG, "Show stack edu: " + shouldShow);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "Show stack edu=%b", shouldShow);
if (shouldShow && BubbleDebugConfig.neverShowUserEducation(mContext)) {
- if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
- Log.d(TAG, "Want to show stack edu, but it is forced hidden");
- }
+ Log.w(TAG, "Want to show stack edu, but it is forced hidden");
return false;
}
return shouldShow;
@@ -1513,7 +1504,7 @@
mBubbleSize = mPositioner.getBubbleSize();
for (Bubble b : mBubbleData.getBubbles()) {
if (b.getIconView() == null) {
- Log.d(TAG, "Display size changed. Icon null: " + b);
+ Log.w(TAG, "Display size changed. Icon null: " + b);
continue;
}
b.getIconView().setLayoutParams(new LayoutParams(mBubbleSize, mBubbleSize));
@@ -1819,10 +1810,6 @@
// via BubbleData.Listener
@SuppressLint("ClickableViewAccessibility")
void addBubble(Bubble bubble) {
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "addBubble: " + bubble);
- }
-
final boolean firstBubble = getBubbleCount() == 0;
if (firstBubble && shouldShowStackEdu()) {
@@ -1868,9 +1855,6 @@
// via BubbleData.Listener
void removeBubble(Bubble bubble) {
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "removeBubble: " + bubble);
- }
if (isExpanded() && getBubbleCount() == 1) {
mRemovingLastBubbleWhileExpanded = true;
// We're expanded while the last bubble is being removed. Let the scrim animate away
@@ -1917,7 +1901,7 @@
bubble.cleanupViews();
logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
} else {
- Log.d(TAG, "was asked to remove Bubble, but didn't find the view! " + bubble);
+ Log.w(TAG, "was asked to remove Bubble, but didn't find the view! " + bubble);
}
}
@@ -1985,10 +1969,6 @@
*/
// via BubbleData.Listener
public void setSelectedBubble(@Nullable BubbleViewProvider bubbleToSelect) {
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "setSelectedBubble: " + bubbleToSelect);
- }
-
if (bubbleToSelect == null) {
mBubbleData.setShowingOverflow(false);
return;
@@ -2081,10 +2061,6 @@
*/
// via BubbleData.Listener
public void setExpanded(boolean shouldExpand) {
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "setExpanded: " + shouldExpand);
- }
-
if (!shouldExpand) {
// If we're collapsing, release the animating-out surface immediately since we have no
// need for it, and this ensures it cannot remain visible as we collapse.
@@ -2126,7 +2102,6 @@
* Monitor for swipe up gesture that is used to collapse expanded view
*/
void startMonitoringSwipeUpGesture() {
- ProtoLog.d(WM_SHELL_BUBBLES, "startMonitoringSwipeUpGesture");
stopMonitoringSwipeUpGestureInternal();
if (isGestureNavEnabled()) {
@@ -2174,7 +2149,6 @@
* Stop monitoring for swipe up gesture
*/
void stopMonitoringSwipeUpGesture() {
- ProtoLog.d(WM_SHELL_BUBBLES, "stopMonitoringSwipeUpGesture");
stopMonitoringSwipeUpGestureInternal();
}
@@ -2202,9 +2176,6 @@
}
void setBubbleSuppressed(Bubble bubble, boolean suppressed) {
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "setBubbleSuppressed: suppressed=" + suppressed + " bubble=" + bubble);
- }
if (suppressed) {
int index = getBubbleIndex(bubble);
mBubbleContainer.removeViewAt(index);
@@ -2339,6 +2310,8 @@
}
private void animateExpansion() {
+ ProtoLog.d(WM_SHELL_BUBBLES, "animateExpansion, expandedBubble=%s",
+ mExpandedBubble != null ? mExpandedBubble.getKey() : "null");
cancelDelayedExpandCollapseSwitchAnimations();
final boolean showVertically = mPositioner.showBubblesVertically();
mIsExpanded = true;
@@ -2465,7 +2438,7 @@
private void animateCollapse() {
cancelDelayedExpandCollapseSwitchAnimations();
-
+ ProtoLog.d(WM_SHELL_BUBBLES, "animateCollapse");
if (isManageEduVisible()) {
mManageEduView.hide();
}
@@ -2508,11 +2481,6 @@
mManageEduView.hide();
}
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "animateCollapse");
- Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
- mExpandedBubble));
- }
updateZOrder();
updateBadges(true /* setBadgeForCollapsedStack */);
afterExpandedViewAnimation();
@@ -2894,7 +2862,7 @@
if (!shouldShowFlyout(bubble)) {
return;
}
-
+ ProtoLog.d(WM_SHELL_BUBBLES, "animateFlyout=%s", bubble.getKey());
mFlyoutDragDeltaX = 0f;
clearFlyoutOnHide();
mAfterFlyoutHidden = () -> {
@@ -3036,6 +3004,9 @@
@VisibleForTesting
public void showManageMenu(boolean show) {
if ((mManageMenu.getVisibility() == VISIBLE) == show) return;
+ ProtoLog.d(WM_SHELL_BUBBLES, "showManageMenu=%b for bubble=%s",
+ show, (mExpandedBubble != null ? mExpandedBubble.getKey() : "null"));
+
mShowingManage = show;
// This should not happen, since the manage menu is only visible when there's an expanded
@@ -3167,10 +3138,6 @@
}
private void updateExpandedBubble() {
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "updateExpandedBubble()");
- }
-
mExpandedViewContainer.removeAllViews();
if (mIsExpanded && mExpandedBubble != null
&& mExpandedBubble.getExpandedView() != null) {
@@ -3318,9 +3285,6 @@
}
private void updateExpandedView() {
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "updateExpandedView: mIsExpanded=" + mIsExpanded);
- }
boolean isOverflowExpanded = mExpandedBubble != null
&& BubbleOverflow.KEY.equals(mExpandedBubble.getKey());
int[] paddings = mPositioner.getExpandedViewContainerPadding(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
index dc27133..530ec5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
@@ -20,7 +20,7 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
@@ -35,6 +35,7 @@
import androidx.annotation.Nullable;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.taskview.TaskView;
/**
@@ -79,11 +80,8 @@
@Override
public void onInitialized() {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onInitialized: destroyed=" + mDestroyed
- + " initialized=" + mInitialized
- + " bubble=" + getBubbleKey());
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: destroyed=%b initialized=%b bubble=%s",
+ mDestroyed, mInitialized, getBubbleKey());
if (mDestroyed || mInitialized) {
return;
@@ -99,10 +97,8 @@
// TODO: I notice inconsistencies in lifecycle
// Post to keep the lifecycle normal
mParentView.post(() -> {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onInitialized: calling startActivity, bubble="
- + getBubbleKey());
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s",
+ getBubbleKey());
try {
options.setTaskAlwaysOnTop(true);
options.setLaunchedFromBubble(true);
@@ -159,10 +155,8 @@
@Override
public void onTaskCreated(int taskId, ComponentName name) {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onTaskCreated: taskId=" + taskId
- + " bubble=" + getBubbleKey());
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "onTaskCreated: taskId=%d bubble=%s",
+ taskId, getBubbleKey());
// The taskId is saved to use for removeTask, preventing appearance in recent tasks.
mTaskId = taskId;
@@ -178,10 +172,8 @@
@Override
public void onTaskRemovalStarted(int taskId) {
- if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "onTaskRemovalStarted: taskId=" + taskId
- + " bubble=" + getBubbleKey());
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "onTaskRemovalStarted: taskId=%d bubble=%s",
+ taskId, getBubbleKey());
if (mBubble != null) {
mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
index 845dca3..e43609f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
@@ -15,14 +15,11 @@
*/
package com.android.wm.shell.bubbles.animation;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_COLLAPSE_ANIMATOR;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_EXPANDED_VIEW_DRAGGING;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.BubbleExpandedView.BACKGROUND_ALPHA;
import static com.android.wm.shell.bubbles.BubbleExpandedView.BOTTOM_CLIP_PROPERTY;
import static com.android.wm.shell.bubbles.BubbleExpandedView.CONTENT_ALPHA;
import static com.android.wm.shell.bubbles.BubbleExpandedView.MANAGE_BUTTON_ALPHA;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -31,7 +28,6 @@
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
-import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.ViewConfiguration;
@@ -41,6 +37,7 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.animation.FlingAnimationUtils;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.bubbles.BubbleExpandedView;
@@ -55,8 +52,6 @@
*/
public class ExpandedViewAnimationControllerImpl implements ExpandedViewAnimationController {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ExpandedViewAnimCtrl" : TAG_BUBBLES;
-
private static final float COLLAPSE_THRESHOLD = 0.02f;
private static final int COLLAPSE_DURATION_MS = 250;
@@ -121,9 +116,6 @@
@Override
public void setExpandedView(BubbleExpandedView expandedView) {
if (mExpandedView != null) {
- if (DEBUG_COLLAPSE_ANIMATOR) {
- Log.d(TAG, "updating expandedView, resetting previous");
- }
if (mCollapseAnimation != null) {
mCollapseAnimation.cancel();
}
@@ -140,17 +132,14 @@
if (mExpandedView != null) {
mDraggedAmount = OverScroll.dampedScroll(distance, mExpandedView.getContentHeight());
- if (DEBUG_COLLAPSE_ANIMATOR && DEBUG_EXPANDED_VIEW_DRAGGING) {
- Log.d(TAG, "updateDrag: distance=" + distance + " dragged=" + mDraggedAmount);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES,
+ "updateDrag: distance=%f dragged=%d", distance, mDraggedAmount);
setCollapsedAmount(mDraggedAmount);
if (!mNotifiedAboutThreshold && isPastCollapseThreshold()) {
mNotifiedAboutThreshold = true;
- if (DEBUG_COLLAPSE_ANIMATOR) {
- Log.d(TAG, "notifying over collapse threshold");
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "notifying over collapse threshold");
vibrateIfEnabled();
}
}
@@ -172,45 +161,35 @@
if (mSwipeDownVelocity > mMinFlingVelocity) {
// Swipe velocity is positive and over fling velocity.
// This is a swipe down, always reset to expanded state, regardless of dragged amount.
- if (DEBUG_COLLAPSE_ANIMATOR) {
- Log.d(TAG,
- "not collapsing expanded view, swipe down velocity: " + mSwipeDownVelocity
- + " minV: " + mMinFlingVelocity);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES,
+ "not collapsing expanded view, swipe down velocity=%f minV=%d",
+ mSwipeDownVelocity, mMinFlingVelocity);
return false;
}
if (mSwipeUpVelocity > mMinFlingVelocity) {
// Swiping up and over fling velocity, collapse the view.
- if (DEBUG_COLLAPSE_ANIMATOR) {
- Log.d(TAG,
- "collapse expanded view, swipe up velocity: " + mSwipeUpVelocity + " minV: "
- + mMinFlingVelocity);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES,
+ "collapse expanded view, swipe up velocity=%f minV=%d",
+ mSwipeUpVelocity, mMinFlingVelocity);
return true;
}
if (isPastCollapseThreshold()) {
- if (DEBUG_COLLAPSE_ANIMATOR) {
- Log.d(TAG, "collapse expanded view, past threshold, dragged: " + mDraggedAmount);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES,
+ "collapse expanded view, past threshold, dragged=%d", mDraggedAmount);
return true;
}
- if (DEBUG_COLLAPSE_ANIMATOR) {
- Log.d(TAG, "not collapsing expanded view");
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "not collapsing expanded view");
return false;
}
@Override
public void animateCollapse(Runnable startStackCollapse, Runnable after) {
- if (DEBUG_COLLAPSE_ANIMATOR) {
- Log.d(TAG,
- "expandedView animate collapse swipeVel=" + mSwipeUpVelocity + " minFlingVel="
- + mMinFlingVelocity);
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "expandedView animate collapse swipeVel=%f minFlingVel=%d",
+ mSwipeUpVelocity, mMinFlingVelocity);
if (mExpandedView != null) {
// Mark it as animating immediately to avoid updates to the view before animation starts
mExpandedView.setAnimating(true);
@@ -243,9 +222,7 @@
@Override
public void animateBackToExpanded() {
- if (DEBUG_COLLAPSE_ANIMATOR) {
- Log.d(TAG, "expandedView animate back to expanded");
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "expandedView animate back to expanded");
BubbleExpandedView expandedView = mExpandedView;
if (expandedView == null) {
return;
@@ -298,9 +275,7 @@
@Override
public void reset() {
- if (DEBUG_COLLAPSE_ANIMATOR) {
- Log.d(TAG, "reset expandedView collapsed state");
- }
+ ProtoLog.d(WM_SHELL_BUBBLES, "reset expandedView collapsed state");
if (mExpandedView == null) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java
index 0c25f27..b3e8bd9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/tracing/PerfettoTransitionTracer.java
@@ -19,16 +19,15 @@
import android.internal.perfetto.protos.PerfettoTrace;
import android.os.SystemClock;
import android.os.Trace;
-import android.tracing.perfetto.DataSourceInstance;
import android.tracing.perfetto.DataSourceParams;
import android.tracing.perfetto.InitArguments;
import android.tracing.perfetto.Producer;
-import android.tracing.perfetto.TracingContext;
import android.tracing.transition.TransitionDataSource;
import android.util.proto.ProtoOutputStream;
import com.android.wm.shell.transition.Transitions;
+import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@@ -41,6 +40,7 @@
mActiveTraces::incrementAndGet,
this::onFlush,
mActiveTraces::decrementAndGet);
+ private final Map<String, Integer> mHandlerMapping = new HashMap<>();
public PerfettoTransitionTracer() {
Producer.init(InitArguments.DEFAULTS);
@@ -69,7 +69,7 @@
private void doLogDispatched(int transitionId, Transitions.TransitionHandler handler) {
mDataSource.trace(ctx -> {
- final int handlerId = getHandlerId(handler, ctx);
+ final int handlerId = getHandlerId(handler);
final ProtoOutputStream os = ctx.newTracePacket();
final long token = os.start(PerfettoTrace.TracePacket.SHELL_TRANSITION);
@@ -81,17 +81,16 @@
});
}
- private static int getHandlerId(Transitions.TransitionHandler handler,
- TracingContext<DataSourceInstance, TransitionDataSource.TlsState, Void> ctx) {
- final Map<String, Integer> handlerMapping =
- ctx.getCustomTlsState().handlerMapping;
+ private int getHandlerId(Transitions.TransitionHandler handler) {
final int handlerId;
- if (handlerMapping.containsKey(handler.getClass().getName())) {
- handlerId = handlerMapping.get(handler.getClass().getName());
- } else {
- // + 1 to avoid 0 ids which can be confused with missing value when dumped to proto
- handlerId = handlerMapping.size() + 1;
- handlerMapping.put(handler.getClass().getName(), handlerId);
+ synchronized (mHandlerMapping) {
+ if (mHandlerMapping.containsKey(handler.getClass().getName())) {
+ handlerId = mHandlerMapping.get(handler.getClass().getName());
+ } else {
+ // + 1 to avoid 0 ids which can be confused with missing value when dumped to proto
+ handlerId = mHandlerMapping.size() + 1;
+ mHandlerMapping.put(handler.getClass().getName(), handlerId);
+ }
}
return handlerId;
}
@@ -194,22 +193,14 @@
}
private void onFlush() {
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "onFlush");
- try {
- doOnFlush();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
- }
-
- private void doOnFlush() {
mDataSource.trace(ctx -> {
final ProtoOutputStream os = ctx.newTracePacket();
- final Map<String, Integer> handlerMapping = ctx.getCustomTlsState().handlerMapping;
- for (String handler : handlerMapping.keySet()) {
+ for (Map.Entry<String, Integer> entry : mHandlerMapping.entrySet()) {
+ final String handler = entry.getKey();
+ final int handlerId = entry.getValue();
final long token = os.start(PerfettoTrace.TracePacket.SHELL_HANDLER_MAPPINGS);
- os.write(PerfettoTrace.ShellHandlerMapping.ID, handlerMapping.get(handler));
+ os.write(PerfettoTrace.ShellHandlerMapping.ID, handlerId);
os.write(PerfettoTrace.ShellHandlerMapping.NAME, handler);
os.end(token);
}
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index c572944..279f9d6 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -484,8 +484,9 @@
WorkDuration& workDuration = *static_cast<WorkDuration*>(workDurationPtr);
VALIDATE_INT(workDuration.workPeriodStartTimestampNanos, > 0)
VALIDATE_INT(workDuration.actualTotalDurationNanos, > 0)
- VALIDATE_INT(workDuration.actualCpuDurationNanos, > 0)
+ VALIDATE_INT(workDuration.actualCpuDurationNanos, >= 0)
VALIDATE_INT(workDuration.actualGpuDurationNanos, >= 0)
+ VALIDATE_INT(workDuration.actualGpuDurationNanos + workDuration.actualCpuDurationNanos, > 0)
return session->reportActualWorkDuration(workDurationPtr);
}
@@ -517,7 +518,7 @@
void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
int64_t actualCpuDurationNanos) {
VALIDATE_PTR(aWorkDuration)
- WARN_INT(actualCpuDurationNanos, > 0)
+ WARN_INT(actualCpuDurationNanos, >= 0)
static_cast<WorkDuration*>(aWorkDuration)->actualCpuDurationNanos = actualCpuDurationNanos;
}
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
index dffe4e2..5d03ef5 100644
--- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
+++ b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
@@ -390,7 +390,8 @@
return;
}
- CrashRecoveryStatsLog.write(CrashRecoveryStatsLog.RESCUE_PARTY_RESET_REPORTED, level);
+ CrashRecoveryStatsLog.write(CrashRecoveryStatsLog.RESCUE_PARTY_RESET_REPORTED,
+ level, levelToString(level));
// Try our best to reset all settings possible, and once finished
// rethrow any exception that we encountered
Exception res = null;
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 09e0d61..bf69d3b 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -45,11 +45,9 @@
<activity android:name=".v2.ui.InstallLaunch"
android:configChanges="orientation|keyboardHidden|screenSize"
- android:theme="@style/Theme.AlertDialogActivity"
android:exported="false"/>
<activity android:name=".InstallStart"
- android:theme="@style/Theme.AlertDialogActivity"
android:exported="true"
android:excludeFromRecents="true">
<intent-filter android:priority="1">
@@ -79,14 +77,12 @@
android:exported="false" />
<activity android:name=".DeleteStagedFileOnResult"
- android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:exported="false" />
<activity android:name=".PackageInstallerActivity"
android:exported="false" />
<activity android:name=".InstallInstalling"
- android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
android:exported="false" />
<receiver android:name=".common.InstallEventReceiver"
@@ -98,16 +94,13 @@
</receiver>
<activity android:name=".InstallSuccess"
- android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
android:exported="false" />
<activity android:name=".InstallFailed"
- android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
android:exported="false" />
<activity android:name=".UninstallerActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
- android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:excludeFromRecents="true"
android:noHistory="true"
android:exported="true">
@@ -121,7 +114,6 @@
<activity android:name=".v2.ui.UninstallLaunch"
android:configChanges="orientation|keyboardHidden|screenSize"
- android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:excludeFromRecents="true"
android:noHistory="true"
android:exported="false">
@@ -144,7 +136,6 @@
</receiver>
<activity android:name=".UninstallUninstalling"
- android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:excludeFromRecents="true"
android:exported="false" />
@@ -171,7 +162,6 @@
<activity android:name=".UnarchiveActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
- android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:excludeFromRecents="true"
android:noHistory="true"
android:exported="true">
@@ -183,7 +173,6 @@
<activity android:name=".UnarchiveErrorActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
- android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:excludeFromRecents="true"
android:noHistory="true"
android:exported="true">
diff --git a/packages/PackageInstaller/res/values/themes.xml b/packages/PackageInstaller/res/values/themes.xml
index 9a06229..f5af510 100644
--- a/packages/PackageInstaller/res/values/themes.xml
+++ b/packages/PackageInstaller/res/values/themes.xml
@@ -17,19 +17,12 @@
<resources>
- <style name="Theme.AlertDialogActivity.NoAnimation"
- parent="@style/Theme.AlertDialogActivity.NoActionBar">
- <item name="android:windowAnimationStyle">@null</item>
- </style>
-
<style name="Theme.AlertDialogActivity"
parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
<item name="alertDialogStyle">@style/AlertDialog</item>
- </style>
-
- <style name="Theme.AlertDialogActivity.NoActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
+ <item name="android:windowAnimationStyle">@null</item>
</style>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1e146a5..e4a762a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1113,6 +1113,10 @@
dumpSetting(s, p,
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
GlobalSettingsProto.Notification.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS);
+ dumpSetting(s, p,
+ Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS,
+ GlobalSettingsProto.Notification
+ .DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS);
p.end(notificationToken);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 16de478..b58187d 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -185,6 +185,7 @@
Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH,
Settings.Global.DEVICE_DEMO_MODE,
Settings.Global.DEVICE_IDLE_CONSTANTS,
+ Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS,
Settings.Global.DISABLE_WINDOW_BLURS,
Settings.Global.BATTERY_SAVER_CONSTANTS,
Settings.Global.BATTERY_TIP_CONSTANTS,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 0050676..f877d7a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -475,6 +475,9 @@
<service android:name=".screenrecord.RecordingService"
android:foregroundServiceType="systemExempted"/>
+ <service android:name=".recordissue.IssueRecordingService"
+ android:foregroundServiceType="systemExempted"/>
+
<receiver android:name=".SysuiRestartReceiver"
android:exported="false">
<intent-filter>
@@ -992,7 +995,6 @@
android:theme="@style/Theme.EditWidgetsActivity"
android:excludeFromRecents="true"
android:autoRemoveFromRecents="true"
- android:showOnLockScreen="true"
android:launchMode="singleTop"
android:exported="false">
</activity>
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/painter/DrawablePainter.kt b/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/painter/DrawablePainter.kt
new file mode 100644
index 0000000..846abf7e
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/painter/DrawablePainter.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2022 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.compose.ui.graphics.painter
+
+import android.graphics.drawable.Animatable
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.os.Handler
+import android.os.Looper
+import android.view.View
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.RememberObserver
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.asAndroidColorFilter
+import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.nativeCanvas
+import androidx.compose.ui.graphics.painter.ColorPainter
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.graphics.withSave
+import androidx.compose.ui.unit.LayoutDirection
+import kotlin.math.roundToInt
+
+/**
+ * *************************************************************************************************
+ * This file was forked from
+ * https://github.com/google/accompanist/blob/main/drawablepainter/src/main/java/com/google/accompanist/drawablepainter/DrawablePainter.kt
+ */
+private val MAIN_HANDLER by lazy(LazyThreadSafetyMode.NONE) { Handler(Looper.getMainLooper()) }
+
+/**
+ * A [Painter] which draws an Android [Drawable] and supports [Animatable] drawables. Instances
+ * should be remembered to be able to start and stop [Animatable] animations.
+ *
+ * Instances are usually retrieved from [rememberDrawablePainter].
+ */
+public class DrawablePainter(public val drawable: Drawable) : Painter(), RememberObserver {
+ private var drawInvalidateTick by mutableStateOf(0)
+ private var drawableIntrinsicSize by mutableStateOf(drawable.intrinsicSize)
+
+ private val callback: Drawable.Callback by lazy {
+ object : Drawable.Callback {
+ override fun invalidateDrawable(d: Drawable) {
+ // Update the tick so that we get re-drawn
+ drawInvalidateTick++
+ // Update our intrinsic size too
+ drawableIntrinsicSize = drawable.intrinsicSize
+ }
+
+ override fun scheduleDrawable(d: Drawable, what: Runnable, time: Long) {
+ MAIN_HANDLER.postAtTime(what, time)
+ }
+
+ override fun unscheduleDrawable(d: Drawable, what: Runnable) {
+ MAIN_HANDLER.removeCallbacks(what)
+ }
+ }
+ }
+
+ init {
+ if (drawable.intrinsicWidth >= 0 && drawable.intrinsicHeight >= 0) {
+ // Update the drawable's bounds to match the intrinsic size
+ drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
+ }
+ }
+
+ override fun onRemembered() {
+ drawable.callback = callback
+ drawable.setVisible(true, true)
+ if (drawable is Animatable) drawable.start()
+ }
+
+ override fun onAbandoned(): Unit = onForgotten()
+
+ override fun onForgotten() {
+ if (drawable is Animatable) drawable.stop()
+ drawable.setVisible(false, false)
+ drawable.callback = null
+ }
+
+ override fun applyAlpha(alpha: Float): Boolean {
+ drawable.alpha = (alpha * 255).roundToInt().coerceIn(0, 255)
+ return true
+ }
+
+ override fun applyColorFilter(colorFilter: ColorFilter?): Boolean {
+ drawable.colorFilter = colorFilter?.asAndroidColorFilter()
+ return true
+ }
+
+ override fun applyLayoutDirection(layoutDirection: LayoutDirection): Boolean {
+ if (Build.VERSION.SDK_INT >= 23) {
+ return drawable.setLayoutDirection(
+ when (layoutDirection) {
+ LayoutDirection.Ltr -> View.LAYOUT_DIRECTION_LTR
+ LayoutDirection.Rtl -> View.LAYOUT_DIRECTION_RTL
+ }
+ )
+ }
+ return false
+ }
+
+ override val intrinsicSize: Size
+ get() = drawableIntrinsicSize
+
+ override fun DrawScope.onDraw() {
+ drawIntoCanvas { canvas ->
+ // Reading this ensures that we invalidate when invalidateDrawable() is called
+ drawInvalidateTick
+
+ // Update the Drawable's bounds
+ drawable.setBounds(0, 0, size.width.roundToInt(), size.height.roundToInt())
+
+ canvas.withSave { drawable.draw(canvas.nativeCanvas) }
+ }
+ }
+}
+
+/**
+ * Remembers [Drawable] wrapped up as a [Painter]. This function attempts to un-wrap the drawable
+ * contents and use Compose primitives where possible.
+ *
+ * If the provided [drawable] is `null`, an empty no-op painter is returned.
+ *
+ * This function tries to dispatch lifecycle events to [drawable] as much as possible from within
+ * Compose.
+ *
+ * @sample com.google.accompanist.sample.drawablepainter.BasicSample
+ */
+@Composable
+public fun rememberDrawablePainter(drawable: Drawable?): Painter =
+ remember(drawable) {
+ when (drawable) {
+ null -> EmptyPainter
+ is ColorDrawable -> ColorPainter(Color(drawable.color))
+ // Since the DrawablePainter will be remembered and it implements RememberObserver, it
+ // will receive the necessary events
+ else -> DrawablePainter(drawable.mutate())
+ }
+ }
+
+private val Drawable.intrinsicSize: Size
+ get() =
+ when {
+ // Only return a finite size if the drawable has an intrinsic size
+ intrinsicWidth >= 0 && intrinsicHeight >= 0 -> {
+ Size(width = intrinsicWidth.toFloat(), height = intrinsicHeight.toFloat())
+ }
+ else -> Size.Unspecified
+ }
+
+internal object EmptyPainter : Painter() {
+ override val intrinsicSize: Size
+ get() = Size.Unspecified
+ override fun DrawScope.onDraw() {}
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index c82688c..5f932f4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -52,7 +52,7 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.SessionTracker
@@ -236,9 +236,7 @@
kosmos = testKosmos()
sceneInteractor = kosmos.sceneInteractor
- keyguardTransitionInteractor =
- KeyguardTransitionInteractorFactory.create(kosmos.testScope.backgroundScope)
- .keyguardTransitionInteractor
+ keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
sceneTransitionStateFlow =
MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Lockscreen))
sceneInteractor.setTransitionState(sceneTransitionStateFlow)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
index 0e257bc..55cfcc2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
@@ -16,44 +16,27 @@
package com.android.systemui.biometrics
-import android.os.Handler
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.biometrics.UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF
import com.android.systemui.biometrics.UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN
-import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
-import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
-import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
-import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor
+import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
-import com.android.systemui.bouncer.ui.BouncerView
-import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
-import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.data.repository.FakeTrustRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.time.SystemClock
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertFalse
@@ -64,9 +47,7 @@
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -77,70 +58,24 @@
@kotlinx.coroutines.ExperimentalCoroutinesApi
class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest :
UdfpsKeyguardViewLegacyControllerBaseTest() {
- private val testDispatcher = StandardTestDispatcher()
- private val testScope = TestScope(testDispatcher)
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
- private lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
- private lateinit var transitionRepository: FakeKeyguardTransitionRepository
-
- @Mock private lateinit var bouncerLogger: TableLogBuffer
+ private val keyguardBouncerRepository = kosmos.fakeKeyguardBouncerRepository
+ private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
@Before
override fun setUp() {
allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread
MockitoAnnotations.initMocks(this)
- keyguardBouncerRepository =
- KeyguardBouncerRepositoryImpl(
- FakeSystemClock(),
- testScope.backgroundScope,
- bouncerLogger,
- )
- transitionRepository = FakeKeyguardTransitionRepository()
super.setUp()
}
override fun createUdfpsKeyguardViewController(): UdfpsKeyguardViewControllerLegacy {
- mPrimaryBouncerInteractor =
- PrimaryBouncerInteractor(
- keyguardBouncerRepository,
- mock(BouncerView::class.java),
- mock(Handler::class.java),
- mKeyguardStateController,
- mock(KeyguardSecurityModel::class.java),
- mock(PrimaryBouncerCallbackInteractor::class.java),
- mock(FalsingCollector::class.java),
- mock(DismissCallbackRegistry::class.java),
- context,
- mKeyguardUpdateMonitor,
- FakeTrustRepository(),
- testScope.backgroundScope,
- mSelectedUserInteractor,
- mock(DeviceEntryFaceAuthInteractor::class.java),
- )
- mAlternateBouncerInteractor =
- AlternateBouncerInteractor(
- mock(StatusBarStateController::class.java),
- mock(KeyguardStateController::class.java),
- keyguardBouncerRepository,
- FakeFingerprintPropertyRepository(),
- mock(BiometricSettingsRepository::class.java),
- mock(SystemClock::class.java),
- mKeyguardUpdateMonitor,
- testScope.backgroundScope,
- )
- mKeyguardTransitionInteractor =
- KeyguardTransitionInteractorFactory.create(
- scope = testScope.backgroundScope,
- repository = transitionRepository,
- )
- .keyguardTransitionInteractor
- mUdfpsOverlayInteractor =
- UdfpsOverlayInteractor(
- context,
- mock(AuthController::class.java),
- mock(SelectedUserInteractor::class.java),
- testScope.backgroundScope,
- )
+ mPrimaryBouncerInteractor = kosmos.primaryBouncerInteractor
+ mAlternateBouncerInteractor = kosmos.alternateBouncerInteractor
+ mKeyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
+ mUdfpsOverlayInteractor = kosmos.udfpsOverlayInteractor
return createUdfpsKeyguardViewController(/* useModernBouncer */ true)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 6808f5d..b611e0a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -37,16 +37,11 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId.fakeInstanceId
import com.android.internal.logging.UiEventLogger
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
-import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
-import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
-import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
-import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
+import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
import com.android.systemui.coroutines.FlowValue
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
@@ -59,52 +54,46 @@
import com.android.systemui.deviceentry.shared.model.FaceDetectionStatus
import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
import com.android.systemui.deviceentry.shared.model.SuccessFaceAuthenticationStatus
-import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.display.data.repository.display
+import com.android.systemui.display.data.repository.displayRepository
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.keyguard.data.repository.BiometricType
-import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeCommandQueue
-import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.data.repository.FakeTrustRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeCommandQueue
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.log.SessionTracker
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.power.data.repository.FakePowerRepository
-import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
-import com.android.systemui.power.domain.interactor.PowerInteractorFactory
+import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.res.R
-import com.android.systemui.statusbar.phone.FakeKeyguardStateController
+import com.android.systemui.statusbar.commandQueue
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.testKosmos
import com.android.systemui.user.data.model.SelectionStatus
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.KotlinArgumentCaptor
import com.android.systemui.util.mockito.captureMany
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.time.SystemClock
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
@@ -129,6 +118,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
+ private val kosmos = testKosmos().apply { this.commandQueue = this.fakeCommandQueue }
private lateinit var underTest: DeviceEntryFaceAuthRepositoryImpl
@Mock private lateinit var faceManager: FaceManager
@@ -136,7 +126,6 @@
@Mock private lateinit var sessionTracker: SessionTracker
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var dumpManager: DumpManager
- @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Captor
private lateinit var authenticationCallback: ArgumentCaptor<FaceManager.AuthenticationCallback>
@@ -151,11 +140,11 @@
@Captor
private lateinit var faceLockoutResetCallback: ArgumentCaptor<FaceManager.LockoutResetCallback>
- private lateinit var testDispatcher: TestDispatcher
+ private val testDispatcher = kosmos.testDispatcher
- private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
- private lateinit var testScope: TestScope
- private lateinit var fakeUserRepository: FakeUserRepository
+ private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ private val testScope = kosmos.testScope
+ private val fakeUserRepository = kosmos.fakeUserRepository
private lateinit var authStatus: FlowValue<FaceAuthenticationStatus?>
private lateinit var detectStatus: FlowValue<FaceDetectionStatus?>
private lateinit var authRunning: FlowValue<Boolean?>
@@ -163,88 +152,30 @@
private lateinit var lockedOut: FlowValue<Boolean?>
private lateinit var canFaceAuthRun: FlowValue<Boolean?>
private lateinit var authenticated: FlowValue<Boolean?>
- private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
- private lateinit var deviceEntryFingerprintAuthRepository:
- FakeDeviceEntryFingerprintAuthRepository
- private lateinit var trustRepository: FakeTrustRepository
- private lateinit var keyguardRepository: FakeKeyguardRepository
- private lateinit var powerRepository: FakePowerRepository
- private lateinit var powerInteractor: PowerInteractor
- private lateinit var keyguardInteractor: KeyguardInteractor
- private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
- private lateinit var displayStateInteractor: DisplayStateInteractor
- private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
- private lateinit var displayRepository: FakeDisplayRepository
- private lateinit var fakeCommandQueue: FakeCommandQueue
+ private val biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository
+ private val deviceEntryFingerprintAuthRepository =
+ kosmos.fakeDeviceEntryFingerprintAuthRepository
+ private val trustRepository = kosmos.fakeTrustRepository
+ private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val powerInteractor = kosmos.powerInteractor
+ private val keyguardInteractor = kosmos.keyguardInteractor
+ private val alternateBouncerInteractor = kosmos.alternateBouncerInteractor
+ private val displayStateInteractor = kosmos.displayStateInteractor
+ private val bouncerRepository = kosmos.fakeKeyguardBouncerRepository
+ private val displayRepository = kosmos.displayRepository
+ private val fakeCommandQueue = kosmos.fakeCommandQueue
+ private val keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
private lateinit var featureFlags: FakeFeatureFlags
- private lateinit var fakeFacePropertyRepository: FakeFacePropertyRepository
private var wasAuthCancelled = false
private var wasDetectCancelled = false
- private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
-
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- testDispatcher = StandardTestDispatcher()
- testScope = TestScope(testDispatcher)
- fakeUserRepository = FakeUserRepository()
fakeUserRepository.setUserInfos(listOf(primaryUser, secondaryUser))
- biometricSettingsRepository = FakeBiometricSettingsRepository()
- deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
- trustRepository = FakeTrustRepository()
featureFlags = FakeFeatureFlags()
- powerRepository = FakePowerRepository()
- powerInteractor =
- PowerInteractorFactory.create(
- repository = powerRepository,
- )
- .powerInteractor
-
- val withDeps =
- KeyguardInteractorFactory.create(
- featureFlags = featureFlags,
- powerInteractor = powerInteractor,
- )
- keyguardInteractor = withDeps.keyguardInteractor
- keyguardRepository = withDeps.repository
- bouncerRepository = withDeps.bouncerRepository
-
- keyguardTransitionRepository = FakeKeyguardTransitionRepository()
- keyguardTransitionInteractor =
- KeyguardTransitionInteractorFactory.create(
- scope = testScope.backgroundScope,
- repository = keyguardTransitionRepository,
- keyguardInteractor = keyguardInteractor,
- )
- .keyguardTransitionInteractor
-
- fakeCommandQueue = withDeps.commandQueue
-
- alternateBouncerInteractor =
- AlternateBouncerInteractor(
- bouncerRepository = bouncerRepository,
- fingerprintPropertyRepository = FakeFingerprintPropertyRepository(),
- biometricSettingsRepository = biometricSettingsRepository,
- systemClock = mock(SystemClock::class.java),
- keyguardStateController = FakeKeyguardStateController(),
- statusBarStateController = mock(StatusBarStateController::class.java),
- keyguardUpdateMonitor = keyguardUpdateMonitor,
- scope = testScope.backgroundScope,
- )
-
- displayRepository = FakeDisplayRepository()
- displayStateInteractor =
- DisplayStateInteractorImpl(
- applicationScope = testScope.backgroundScope,
- context = context,
- mainExecutor = FakeExecutor(FakeSystemClock()),
- displayStateRepository = FakeDisplayStateRepository(),
- displayRepository = displayRepository,
- )
-
bypassStateChangedListener =
KotlinArgumentCaptor(KeyguardBypassController.OnBypassStateChangedListener::class.java)
whenever(sessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(keyguardSessionId)
@@ -282,7 +213,6 @@
testScope.backgroundScope
)
- fakeFacePropertyRepository = FakeFacePropertyRepository()
return DeviceEntryFaceAuthRepositoryImpl(
mContext,
fmOverride,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
index 98f0211..9d34903 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
@@ -18,23 +18,27 @@
package com.android.systemui.keyguard.domain.interactor
import android.content.Intent
+import android.view.accessibility.accessibilityManagerWrapper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.internal.logging.uiEventLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -43,7 +47,6 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -51,27 +54,25 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class KeyguardLongPressInteractorTest : SysuiTestCase() {
-
- @Mock private lateinit var logger: UiEventLogger
- @Mock private lateinit var accessibilityManager: AccessibilityManagerWrapper
+ private val kosmos =
+ testKosmos().apply {
+ this.accessibilityManagerWrapper = mock<AccessibilityManagerWrapper>()
+ this.uiEventLogger = mock<UiEventLoggerFake>()
+ }
private lateinit var underTest: KeyguardLongPressInteractor
- private lateinit var testScope: TestScope
- private lateinit var keyguardRepository: FakeKeyguardRepository
- private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+ private val logger = kosmos.uiEventLogger
+ private val testScope = kosmos.testScope
+ private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
overrideResource(R.bool.long_press_keyguard_customize_lockscreen_enabled, true)
- whenever(accessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenAnswer {
- it.arguments[0]
- }
-
- testScope = TestScope()
- keyguardRepository = FakeKeyguardRepository()
- keyguardTransitionRepository = FakeKeyguardTransitionRepository()
+ whenever(kosmos.accessibilityManagerWrapper.getRecommendedTimeoutMillis(anyInt(), anyInt()))
+ .thenAnswer { it.arguments[0] }
runBlocking { createUnderTest() }
}
@@ -284,25 +285,22 @@
isRevampedWppFeatureEnabled: Boolean = true,
isOpenWppDirectlyEnabled: Boolean = false,
) {
+ // This needs to be re-created for each test outside of kosmos since the flag values are
+ // read during initialization to set up flows. Maybe there is a better way to handle that.
underTest =
KeyguardLongPressInteractor(
appContext = mContext,
scope = testScope.backgroundScope,
- transitionInteractor =
- KeyguardTransitionInteractorFactory.create(
- scope = testScope.backgroundScope,
- repository = keyguardTransitionRepository,
- )
- .keyguardTransitionInteractor,
+ transitionInteractor = kosmos.keyguardTransitionInteractor,
repository = keyguardRepository,
logger = logger,
featureFlags =
- FakeFeatureFlags().apply {
+ kosmos.fakeFeatureFlagsClassic.apply {
set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, isLongPressFeatureEnabled)
set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, isOpenWppDirectlyEnabled)
},
broadcastDispatcher = fakeBroadcastDispatcher,
- accessibilityManager = accessibilityManager
+ accessibilityManager = kosmos.accessibilityManagerWrapper
)
setUpState()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
index ce43d4e..9b302ae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -19,23 +19,23 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.fakeLightRevealScrimRepository
import com.android.systemui.keyguard.data.repository.FakeLightRevealScrimRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.LightRevealEffect
import com.android.systemui.statusbar.LightRevealScrim
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.testKosmos
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
@@ -43,29 +43,22 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class LightRevealScrimInteractorTest : SysuiTestCase() {
- private val fakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository()
+ val kosmos =
+ testKosmos().apply {
+ this.fakeLightRevealScrimRepository = Mockito.spy(FakeLightRevealScrimRepository())
+ }
- private val fakeLightRevealScrimRepository by lazy {
- Mockito.spy(FakeLightRevealScrimRepository())
- }
+ private val fakeLightRevealScrimRepository = kosmos.fakeLightRevealScrimRepository
- private val testScope = TestScope()
+ private val fakeKeyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ private val testScope = kosmos.testScope
- private val keyguardTransitionInteractor by lazy {
- KeyguardTransitionInteractorFactory.create(
- scope = testScope.backgroundScope,
- repository = fakeKeyguardTransitionRepository,
- )
- .keyguardTransitionInteractor
- }
-
- private lateinit var underTest: LightRevealScrimInteractor
+ private val underTest = kosmos.lightRevealScrimInteractor
private val reveal1 =
object : LightRevealEffect {
@@ -77,19 +70,6 @@
override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {}
}
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- underTest =
- LightRevealScrimInteractor(
- keyguardTransitionInteractor,
- fakeLightRevealScrimRepository,
- testScope.backgroundScope,
- mock(),
- mock()
- )
- }
-
@Test
fun lightRevealEffect_doesNotChangeDuringKeyguardTransition() =
runTest(UnconfinedTestDispatcher()) {
diff --git a/packages/SystemUI/res/color/brightness_slider_track.xml b/packages/SystemUI/res/color/brightness_slider_track.xml
new file mode 100644
index 0000000..6028769
--- /dev/null
+++ b/packages/SystemUI/res/color/brightness_slider_track.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral2_500" android:lStar="40" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
index 95c7778c..cae9d6b 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
@@ -24,7 +24,7 @@
<shape>
<size android:height="@dimen/rounded_slider_track_width" />
<corners android:radius="@dimen/rounded_slider_track_corner_radius" />
- <solid android:color="?attr/shadeInactive" />
+ <solid android:color="@color/brightness_slider_track" />
</shape>
</inset>
</item>
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index 6e541a7..ce09385 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -49,7 +49,7 @@
android:layout_centerVertical="true"
android:paddingTop="1dp"
android:importantForAccessibility="yes"
- android:tint="#9E9E9E" />
+ android:tint="?android:attr/textColorPrimary"/>
<TextView
android:id="@+id/undo"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8971859..f0cbe7a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -305,6 +305,27 @@
<!-- A toast message shown when the screen recording cannot be started due to a generic error [CHAR LIMIT=NONE] -->
<string name="screenrecord_start_error">Error starting screen recording</string>
+ <!-- Notification title displayed for issue recording [CHAR LIMIT=50]-->
+ <string name="issuerecord_title">Issue Recorder</string>
+ <!-- Processing issue recoding data in the background [CHAR LIMIT=30]-->
+ <string name="issuerecord_background_processing_label">Processing issue recording</string>
+ <!-- Description of the screen recording notification channel [CHAR LIMIT=NONE]-->
+ <string name="issuerecord_channel_description">Ongoing notification for an issue collection session</string>
+
+ <!-- Notification text displayed when we are recording the screen [CHAR LIMIT=100]-->
+ <string name="issuerecord_ongoing_screen_only">Recording issue</string>
+ <!-- Label for notification action to share issue recording [CHAR LIMIT=35] -->
+ <string name="issuerecord_share_label">Share</string>
+ <!-- A toast message shown after successfully canceling a issue recording [CHAR LIMIT=NONE] -->
+ <!-- Notification text shown after saving a issue recording [CHAR LIMIT=100] -->
+ <string name="issuerecord_save_title">Issue recording saved</string>
+ <!-- Subtext for a notification shown after saving a issue recording to prompt the user to view it [CHAR_LIMIT=100] -->
+ <string name="issuerecord_save_text">Tap to view</string>
+ <!-- A toast message shown when there is an error saving a issue recording [CHAR LIMIT=NONE] -->
+ <string name="issuerecord_save_error">Error saving issue recording</string>
+ <!-- A toast message shown when the issue recording cannot be started due to a generic error [CHAR LIMIT=NONE] -->
+ <string name="issuerecord_start_error">Error starting issue recording</string>
+
<!-- Cling help message title when hiding the navigation bar entering immersive mode [CHAR LIMIT=none] -->
<string name="immersive_cling_title">Viewing full screen</string>
<!-- Cling help message description when hiding the navigation bar entering immersive mode [CHAR LIMIT=none] -->
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index 92eeace..904d5898 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -23,6 +23,7 @@
import com.android.systemui.dreams.DreamOverlayService;
import com.android.systemui.dump.SystemUIAuxiliaryDumpService;
import com.android.systemui.keyguard.KeyguardService;
+import com.android.systemui.recordissue.IssueRecordingService;
import com.android.systemui.screenrecord.RecordingService;
import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
import com.android.systemui.wallpapers.ImageWallpaper;
@@ -85,4 +86,11 @@
@IntoMap
@ClassKey(RecordingService.class)
public abstract Service bindRecordingService(RecordingService service);
+
+ /** Inject into IssueRecordingService */
+ @Binds
+ @IntoMap
+ @ClassKey(IssueRecordingService.class)
+ public abstract Service bindIssueRecordingService(IssueRecordingService service);
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 53c81e5..e18e463 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -109,7 +109,7 @@
* This animation will take place entirely within the Launcher window. We can safely unlock the
* device, end remote animations, etc. even if this is still running.
*/
-const val LAUNCHER_ICONS_ANIMATION_DURATION_MS = 633L
+const val LAUNCHER_ICONS_ANIMATION_DURATION_MS = 1633L
/**
* How long to wait for the shade to get out of the way before starting the canned unlock animation.
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
index 16dfc21..47df021 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
@@ -32,6 +32,7 @@
import android.util.MathUtils.lerpInvSat
import androidx.annotation.VisibleForTesting
import com.android.app.animation.Interpolators
+import com.android.app.tracing.traceSection
import com.android.internal.graphics.ColorUtils
import kotlin.math.abs
import kotlin.math.cos
@@ -127,6 +128,10 @@
}
override fun draw(canvas: Canvas) {
+ traceSection("SquigglyProgress#draw") { drawTraced(canvas) }
+ }
+
+ private fun drawTraced(canvas: Canvas) {
if (animate) {
invalidateSelf()
val now = SystemClock.uptimeMillis()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 53f287b..720120b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -47,6 +47,8 @@
public static final long QS_ANIM_LENGTH = 350;
+ private static final long ICON_APPLIED_TRANSACTION_ID = -1;
+
protected final View mIcon;
protected int mIconSizePx;
private boolean mAnimationEnabled = true;
@@ -57,7 +59,8 @@
@VisibleForTesting
QSTile.Icon mLastIcon;
- private boolean mIconChangeScheduled;
+ private long mScheduledIconChangeTransactionId = ICON_APPLIED_TRANSACTION_ID;
+ private long mHighestScheduledIconChangeTransactionId = ICON_APPLIED_TRANSACTION_ID;
private ValueAnimator mColorAnimator = new ValueAnimator();
@@ -117,7 +120,7 @@
}
protected void updateIcon(ImageView iv, State state, boolean allowAnimations) {
- mIconChangeScheduled = false;
+ mScheduledIconChangeTransactionId = ICON_APPLIED_TRANSACTION_ID;
final QSTile.Icon icon = state.iconSupplier != null ? state.iconSupplier.get() : state.icon;
if (!Objects.equals(icon, iv.getTag(R.id.qs_icon_tag))) {
boolean shouldAnimate = allowAnimations && shouldAnimate(iv);
@@ -173,9 +176,10 @@
mState = state.state;
mDisabledByPolicy = state.disabledByPolicy;
if (mTint != 0 && allowAnimations && shouldAnimate(iv)) {
- mIconChangeScheduled = true;
+ final long iconTransactionId = getNextIconTransactionId();
+ mScheduledIconChangeTransactionId = iconTransactionId;
animateGrayScale(mTint, color, iv, () -> {
- if (mIconChangeScheduled) {
+ if (mScheduledIconChangeTransactionId == iconTransactionId) {
updateIcon(iv, state, allowAnimations);
}
});
@@ -237,6 +241,11 @@
child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
}
+ private long getNextIconTransactionId() {
+ mHighestScheduledIconChangeTransactionId++;
+ return mHighestScheduledIconChangeTransactionId;
+ }
+
/**
* Color to tint the tile icon based on state
*/
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index 88863cb..a474868 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -42,6 +42,7 @@
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.recordissue.IssueRecordingService
import com.android.systemui.recordissue.RecordIssueDialogDelegate
import com.android.systemui.res.R
import com.android.systemui.screenrecord.RecordingService
@@ -107,7 +108,7 @@
PendingIntent.getService(
userContextProvider.userContext,
RecordingService.REQUEST_CODE,
- RecordingService.getStopIntent(userContextProvider.userContext),
+ IssueRecordingService.getStopIntent(userContextProvider.userContext),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
.send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
new file mode 100644
index 0000000..f487258
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2024 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.recordissue
+
+import android.app.NotificationManager
+import android.content.Context
+import android.content.Intent
+import android.content.res.Resources
+import android.os.Handler
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.qualifiers.LongRunning
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.res.R
+import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.screenrecord.RecordingService
+import com.android.systemui.screenrecord.RecordingServiceStrings
+import com.android.systemui.settings.UserContextProvider
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+class IssueRecordingService
+@Inject
+constructor(
+ controller: RecordingController,
+ @LongRunning executor: Executor,
+ @Main handler: Handler,
+ uiEventLogger: UiEventLogger,
+ notificationManager: NotificationManager,
+ userContextProvider: UserContextProvider,
+ keyguardDismissUtil: KeyguardDismissUtil
+) :
+ RecordingService(
+ controller,
+ executor,
+ handler,
+ uiEventLogger,
+ notificationManager,
+ userContextProvider,
+ keyguardDismissUtil
+ ) {
+
+ override fun getTag(): String = TAG
+
+ override fun getChannelId(): String = CHANNEL_ID
+
+ override fun provideRecordingServiceStrings(): RecordingServiceStrings = IrsStrings(resources)
+
+ companion object {
+ private const val TAG = "IssueRecordingService"
+ private const val CHANNEL_ID = "issue_record"
+
+ /**
+ * Get an intent to stop the issue recording service.
+ *
+ * @param context Context from the requesting activity
+ * @return
+ */
+ fun getStopIntent(context: Context): Intent =
+ Intent(context, RecordingService::class.java)
+ .setAction(ACTION_STOP)
+ .putExtra(Intent.EXTRA_USER_HANDLE, context.userId)
+
+ /**
+ * Get an intent to start the issue recording service.
+ *
+ * @param context Context from the requesting activity
+ */
+ fun getStartIntent(context: Context): Intent =
+ Intent(context, RecordingService::class.java).setAction(ACTION_START)
+ }
+}
+
+private class IrsStrings(private val res: Resources) : RecordingServiceStrings(res) {
+ override val title
+ get() = res.getString(R.string.issuerecord_title)
+ override val notificationChannelDescription
+ get() = res.getString(R.string.issuerecord_channel_description)
+ override val startErrorResId
+ get() = R.string.issuerecord_start_error
+ override val startError
+ get() = res.getString(R.string.issuerecord_start_error)
+ override val saveErrorResId
+ get() = R.string.issuerecord_save_error
+ override val saveError
+ get() = res.getString(R.string.issuerecord_save_error)
+ override val ongoingRecording
+ get() = res.getString(R.string.issuerecord_ongoing_screen_only)
+ override val backgroundProcessingLabel
+ get() = res.getString(R.string.issuerecord_background_processing_label)
+ override val saveTitle
+ get() = res.getString(R.string.issuerecord_save_title)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index e051df4..80f11f1 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -17,7 +17,6 @@
package com.android.systemui.recordissue
import android.annotation.SuppressLint
-import android.app.Activity
import android.app.BroadcastOptions
import android.app.PendingIntent
import android.content.Context
@@ -45,7 +44,6 @@
import com.android.systemui.qs.tiles.RecordIssueTile
import com.android.systemui.res.R
import com.android.systemui.screenrecord.RecordingService
-import com.android.systemui.screenrecord.ScreenRecordingAudioSource
import com.android.systemui.settings.UserContextProvider
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
@@ -183,13 +181,7 @@
PendingIntent.getForegroundService(
userContextProvider.userContext,
RecordingService.REQUEST_CODE,
- RecordingService.getStartIntent(
- userContextProvider.userContext,
- Activity.RESULT_OK,
- ScreenRecordingAudioSource.NONE.ordinal,
- false,
- null
- ),
+ IssueRecordingService.getStartIntent(userContextProvider.userContext),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
.send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index b5a1313..b355d2d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -24,7 +24,6 @@
import android.app.Service;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.media.MediaRecorder;
import android.net.Uri;
@@ -71,8 +70,8 @@
private static final String EXTRA_SHOW_TAPS = "extra_showTaps";
private static final String EXTRA_CAPTURE_TARGET = "extra_captureTarget";
- private static final String ACTION_START = "com.android.systemui.screenrecord.START";
- private static final String ACTION_STOP = "com.android.systemui.screenrecord.STOP";
+ protected static final String ACTION_START = "com.android.systemui.screenrecord.START";
+ protected static final String ACTION_STOP = "com.android.systemui.screenrecord.STOP";
private static final String ACTION_STOP_NOTIF =
"com.android.systemui.screenrecord.STOP_FROM_NOTIF";
private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
@@ -90,6 +89,7 @@
private final NotificationManager mNotificationManager;
private final UserContextProvider mUserContextTracker;
private int mNotificationId = NOTIF_BASE_ID;
+ private RecordingServiceStrings mStrings;
@Inject
public RecordingService(RecordingController controller, @LongRunning Executor executor,
@@ -134,9 +134,9 @@
return Service.START_NOT_STICKY;
}
String action = intent.getAction();
- Log.d(TAG, "onStartCommand " + action);
+ Log.d(getTag(), "onStartCommand " + action);
NotificationChannel channel = new NotificationChannel(
- CHANNEL_ID,
+ getChannelId(),
getString(R.string.screenrecord_title),
NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(getString(R.string.screenrecord_channel_description));
@@ -152,7 +152,7 @@
mNotificationId = NOTIF_BASE_ID + (int) SystemClock.uptimeMillis();
mAudioSource = ScreenRecordingAudioSource
.values()[intent.getIntExtra(EXTRA_AUDIO_SOURCE, 0)];
- Log.d(TAG, "recording with audio source " + mAudioSource);
+ Log.d(getTag(), "recording with audio source " + mAudioSource);
mShowTaps = intent.getBooleanExtra(EXTRA_SHOW_TAPS, false);
MediaProjectionCaptureTarget captureTarget =
intent.getParcelableExtra(EXTRA_CAPTURE_TARGET,
@@ -207,7 +207,7 @@
.setType("video/mp4")
.putExtra(Intent.EXTRA_STREAM, shareUri);
mKeyguardDismissUtil.executeWhenUnlocked(() -> {
- String shareLabel = getResources().getString(R.string.screenrecord_share_label);
+ String shareLabel = strings().getShareLabel();
startActivity(Intent.createChooser(shareIntent, shareLabel)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
// Remove notification
@@ -270,13 +270,11 @@
*/
@VisibleForTesting
protected void createErrorNotification() {
- Resources res = getResources();
Bundle extras = new Bundle();
- extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- res.getString(R.string.screenrecord_title));
- String notificationTitle = res.getString(R.string.screenrecord_start_error);
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, strings().getTitle());
+ String notificationTitle = strings().getStartError();
- Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
+ Notification.Builder builder = new Notification.Builder(this, getChannelId())
.setSmallIcon(R.drawable.ic_screenrecord)
.setContentTitle(notificationTitle)
.addExtras(extras);
@@ -290,14 +288,12 @@
@VisibleForTesting
protected void createRecordingNotification() {
- Resources res = getResources();
Bundle extras = new Bundle();
- extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- res.getString(R.string.screenrecord_title));
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, strings().getTitle());
String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
- ? res.getString(R.string.screenrecord_ongoing_screen_only)
- : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
+ ? strings().getOngoingRecording()
+ : strings().getOngoingRecordingWithAudio();
PendingIntent pendingIntent = PendingIntent.getService(
this,
@@ -306,9 +302,9 @@
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Notification.Action stopAction = new Notification.Action.Builder(
Icon.createWithResource(this, R.drawable.ic_android),
- getResources().getString(R.string.screenrecord_stop_label),
+ strings().getStopLabel(),
pendingIntent).build();
- Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
+ Notification.Builder builder = new Notification.Builder(this, getChannelId())
.setSmallIcon(R.drawable.ic_screenrecord)
.setContentTitle(notificationTitle)
.setUsesChronometer(true)
@@ -323,19 +319,17 @@
@VisibleForTesting
protected Notification createProcessingNotification() {
- Resources res = getApplicationContext().getResources();
String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
- ? res.getString(R.string.screenrecord_ongoing_screen_only)
- : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
+ ? strings().getOngoingRecording()
+ : strings().getOngoingRecordingWithAudio();
Bundle extras = new Bundle();
- extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- res.getString(R.string.screenrecord_title));
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, strings().getTitle());
- Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
+ Notification.Builder builder = new Notification.Builder(this, getChannelId())
.setContentTitle(notificationTitle)
.setContentText(
- getResources().getString(R.string.screenrecord_background_processing_label))
+ strings().getBackgroundProcessingLabel())
.setSmallIcon(R.drawable.ic_screenrecord)
.setGroup(GROUP_KEY)
.addExtras(extras);
@@ -351,7 +345,7 @@
Notification.Action shareAction = new Notification.Action.Builder(
Icon.createWithResource(this, R.drawable.ic_screenrecord),
- getResources().getString(R.string.screenrecord_share_label),
+ strings().getShareLabel(),
PendingIntent.getService(
this,
REQUEST_CODE,
@@ -360,13 +354,12 @@
.build();
Bundle extras = new Bundle();
- extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- getResources().getString(R.string.screenrecord_title));
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, strings().getTitle());
- Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
+ Notification.Builder builder = new Notification.Builder(this, getChannelId())
.setSmallIcon(R.drawable.ic_screenrecord)
- .setContentTitle(getResources().getString(R.string.screenrecord_save_title))
- .setContentText(getResources().getString(R.string.screenrecord_save_text))
+ .setContentTitle(strings().getSaveTitle())
+ .setContentText(strings().getSaveText())
.setContentIntent(PendingIntent.getActivity(
this,
REQUEST_CODE,
@@ -394,15 +387,15 @@
private void postGroupNotification(UserHandle currentUser) {
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- getResources().getString(R.string.screenrecord_title));
- Notification groupNotif = new Notification.Builder(this, CHANNEL_ID)
+ strings().getTitle());
+ Notification groupNotif = new Notification.Builder(this, getChannelId())
.setSmallIcon(R.drawable.ic_screenrecord)
- .setContentTitle(getResources().getString(R.string.screenrecord_save_title))
+ .setContentTitle(strings().getSaveTitle())
.setGroup(GROUP_KEY)
.setGroupSummary(true)
.setExtras(extras)
.build();
- mNotificationManager.notifyAsUser(TAG, NOTIF_BASE_ID, groupNotif, currentUser);
+ mNotificationManager.notifyAsUser(getTag(), NOTIF_BASE_ID, groupNotif, currentUser);
}
private void stopService() {
@@ -413,7 +406,7 @@
if (userId == USER_ID_NOT_SPECIFIED) {
userId = mUserContextTracker.getUserContext().getUserId();
}
- Log.d(TAG, "notifying for user " + userId);
+ Log.d(getTag(), "notifying for user " + userId);
setTapsVisible(mOriginalShowTaps);
if (getRecorder() != null) {
try {
@@ -424,7 +417,7 @@
// let's release the recorder and delete all temporary files in this case
getRecorder().release();
showErrorToast(R.string.screenrecord_start_error);
- Log.e(TAG, "stopRecording called, but there was an error when ending"
+ Log.e(getTag(), "stopRecording called, but there was an error when ending"
+ "recording");
exception.printStackTrace();
createErrorNotification();
@@ -435,7 +428,7 @@
throw new RuntimeException(throwable);
}
} else {
- Log.e(TAG, "stopRecording called, but recorder was null");
+ Log.e(getTag(), "stopRecording called, but recorder was null");
}
updateState(false);
stopForeground(STOP_FOREGROUND_DETACH);
@@ -449,13 +442,13 @@
mLongExecutor.execute(() -> {
try {
- Log.d(TAG, "saving recording");
+ Log.d(getTag(), "saving recording");
Notification notification = createSaveNotification(getRecorder().save());
postGroupNotification(currentUser);
mNotificationManager.notifyAsUser(null, mNotificationId, notification,
currentUser);
} catch (IOException | IllegalStateException e) {
- Log.e(TAG, "Error saving screen recording: " + e.getMessage());
+ Log.e(getTag(), "Error saving screen recording: " + e.getMessage());
e.printStackTrace();
showErrorToast(R.string.screenrecord_save_error);
mNotificationManager.cancelAsUser(null, mNotificationId, currentUser);
@@ -468,6 +461,26 @@
Settings.System.putInt(getContentResolver(), Settings.System.SHOW_TOUCHES, value);
}
+ protected String getTag() {
+ return TAG;
+ }
+
+ protected String getChannelId() {
+ return CHANNEL_ID;
+ }
+
+ private RecordingServiceStrings strings() {
+ if (mStrings == null) {
+ mStrings = provideRecordingServiceStrings();
+ }
+ return mStrings;
+ }
+
+ protected RecordingServiceStrings provideRecordingServiceStrings() {
+ return new RecordingServiceStrings(getResources());
+ }
+
+
/**
* Get an intent to stop the recording service.
* @param context Context from the requesting activity
@@ -484,25 +497,25 @@
* @param context
* @return
*/
- protected static Intent getNotificationIntent(Context context) {
- return new Intent(context, RecordingService.class).setAction(ACTION_STOP_NOTIF);
+ protected Intent getNotificationIntent(Context context) {
+ return new Intent(context, this.getClass()).setAction(ACTION_STOP_NOTIF);
}
- private static Intent getShareIntent(Context context, String path) {
- return new Intent(context, RecordingService.class).setAction(ACTION_SHARE)
+ private Intent getShareIntent(Context context, String path) {
+ return new Intent(context, this.getClass()).setAction(ACTION_SHARE)
.putExtra(EXTRA_PATH, path);
}
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
- Log.d(TAG, "Media recorder info: " + what);
+ Log.d(getTag(), "Media recorder info: " + what);
onStartCommand(getStopIntent(this), 0, 0);
}
@Override
public void onStopped() {
if (mController.isRecording()) {
- Log.d(TAG, "Stopping recording because the system requested the stop");
+ Log.d(getTag(), "Stopping recording because the system requested the stop");
stopService();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingServiceStrings.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingServiceStrings.kt
new file mode 100644
index 0000000..fdb1eb6a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingServiceStrings.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 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.screenrecord
+
+import android.content.res.Resources
+import com.android.systemui.res.R
+
+open class RecordingServiceStrings(private val res: Resources) {
+ open val title
+ get() = res.getString(R.string.screenrecord_title)
+ open val notificationChannelDescription
+ get() = res.getString(R.string.screenrecord_channel_description)
+ open val startErrorResId
+ get() = R.string.screenrecord_start_error
+ open val startError
+ get() = res.getString(R.string.screenrecord_start_error)
+ open val saveErrorResId
+ get() = R.string.screenrecord_save_error
+ open val saveError
+ get() = res.getString(R.string.screenrecord_save_error)
+ open val ongoingRecording
+ get() = res.getString(R.string.screenrecord_ongoing_screen_only)
+ open val backgroundProcessingLabel
+ get() = res.getString(R.string.screenrecord_background_processing_label)
+ open val saveTitle
+ get() = res.getString(R.string.screenrecord_save_title)
+
+ val saveText
+ get() = res.getString(R.string.screenrecord_save_text)
+ val ongoingRecordingWithAudio
+ get() = res.getString(R.string.screenrecord_ongoing_screen_and_audio)
+ val stopLabel
+ get() = res.getString(R.string.screenrecord_stop_label)
+ val shareLabel
+ get() = res.getString(R.string.screenrecord_share_label)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerShelfViewBinder.kt
index 783488af..4e40888 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerShelfViewBinder.kt
@@ -37,11 +37,12 @@
) {
suspend fun bind(view: NotificationIconContainer) {
viewModel.icons.bindIcons(
- view,
- configuration,
- systemBarUtilsState,
+ logTag = "shelf",
+ view = view,
+ configuration = configuration,
+ systemBarUtilsState = systemBarUtilsState,
notifyBindingFailures = { failureTracker.shelfFailures = it },
- viewStore,
+ viewStore = viewStore,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index f375ebc..de3a626 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -72,11 +72,12 @@
val iconColors: StateFlow<NotificationIconColors> =
viewModel.iconColors.mapNotNull { it.iconColors(view.viewBounds) }.stateIn(this)
viewModel.icons.bindIcons(
- view,
- configuration,
- systemBarUtilsState,
+ logTag = "statusbar",
+ view = view,
+ configuration = configuration,
+ systemBarUtilsState = systemBarUtilsState,
notifyBindingFailures = { failureTracker.statusBarFailures = it },
- viewStore,
+ viewStore = viewStore,
) { _, sbiv ->
StatusBarIconViewBinder.bindIconColors(
sbiv,
@@ -124,11 +125,12 @@
val tintAlpha = viewModel.tintAlpha.stateIn(this)
val animsEnabled = viewModel.areIconAnimationsEnabled.stateIn(this)
viewModel.icons.bindIcons(
- view,
- configuration,
- systemBarUtilsState,
+ logTag = "aod",
+ view = view,
+ configuration = configuration,
+ systemBarUtilsState = systemBarUtilsState,
notifyBindingFailures = { failureTracker.aodFailures = it },
- viewStore,
+ viewStore = viewStore,
) { _, sbiv ->
coroutineScope {
launch { StatusBarIconViewBinder.bindColor(sbiv, color) }
@@ -176,6 +178,7 @@
* view is to be unbound.
*/
suspend fun Flow<NotificationIconsViewData>.bindIcons(
+ logTag: String,
view: NotificationIconContainer,
configuration: ConfigurationState,
systemBarUtilsState: SystemBarUtilsState,
@@ -197,7 +200,7 @@
}
.stateIn(this)
try {
- bindIcons(view, layoutParams, notifyBindingFailures, viewStore, bindIcon)
+ bindIcons(logTag, view, layoutParams, notifyBindingFailures, viewStore, bindIcon)
} finally {
// Detach everything so that child SBIVs don't hold onto a reference to the container.
view.detachAllIcons()
@@ -205,6 +208,7 @@
}
private suspend fun Flow<NotificationIconsViewData>.bindIcons(
+ logTag: String,
view: NotificationIconContainer,
layoutParams: StateFlow<FrameLayout.LayoutParams>,
notifyBindingFailures: (Collection<String>) -> Unit,
@@ -214,7 +218,7 @@
val failedBindings = mutableSetOf<String>()
val boundViewsByNotifKey = ArrayMap<String, Pair<StatusBarIconView, Job>>()
var prevIcons = NotificationIconsViewData()
- collectTracingEach("NIC#bindIcons") { iconsData: NotificationIconsViewData ->
+ collectTracingEach({ "NIC($logTag)#bindIcons" }) { iconsData: NotificationIconsViewData ->
val iconsDiff = NotificationIconsViewData.computeDifference(iconsData, prevIcons)
prevIcons = iconsData
@@ -249,7 +253,7 @@
if (this !== view) {
Log.wtf(
TAG,
- "StatusBarIconView($notifKey) has an unexpected parent",
+ "[$logTag] SBIV($notifKey) has an unexpected parent",
)
}
// If the container was re-inflated and re-bound, then SBIVs might still
@@ -266,7 +270,9 @@
sbiv,
launch {
launch {
- layoutParams.collectTracingEach("SBIV#bindLayoutParams") {
+ layoutParams.collectTracingEach(
+ tag = { "[$logTag] SBIV#bindLayoutParams" },
+ ) {
if (it != sbiv.layoutParams) {
sbiv.layoutParams = it
}
@@ -307,7 +313,12 @@
val childCount = view.childCount
for (i in 0 until childCount) {
val actual = view.getChildAt(i)
- val expected = expectedChildren[i]
+ val expected = expectedChildren.getOrNull(i)
+ if (expected == null) {
+ Log.wtf(TAG, "[$logTag] Unexpected child $actual")
+ view.removeView(actual)
+ continue
+ }
if (actual === expected) {
continue
}
@@ -379,3 +390,11 @@
tag: String,
crossinline collector: (T) -> Unit,
) = collect { traceSection(tag) { collector(it) } }
+
+private suspend inline fun <T> Flow<T>.collectTracingEach(
+ noinline tag: () -> String,
+ crossinline collector: (T) -> Unit,
+) {
+ val lazyTag = lazy(mode = LazyThreadSafetyMode.PUBLICATION, tag)
+ collect { traceSection({ lazyTag.value }) { collector(it) } }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
index 11e374f..d4c180d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
@@ -18,25 +18,36 @@
import static com.android.server.notification.Flags.screenshareNotificationHiding;
+import android.annotation.MainThread;
+import android.app.IActivityManager;
+import android.content.Context;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Handler;
+import android.os.RemoteException;
import android.os.Trace;
import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.util.Assert;
import com.android.systemui.util.ListenerSet;
+import java.util.concurrent.Executor;
+
import javax.inject.Inject;
/** Implementation of SensitiveNotificationProtectionController. **/
@SysUISingleton
public class SensitiveNotificationProtectionControllerImpl
implements SensitiveNotificationProtectionController {
- private final MediaProjectionManager mMediaProjectionManager;
+ private static final String LOG_TAG = "SNPC";
+ private final ArraySet<String> mExemptPackages = new ArraySet<>();
private final ListenerSet<Runnable> mListeners = new ListenerSet<>();
private volatile MediaProjectionInfo mProjection;
@@ -45,44 +56,100 @@
new MediaProjectionManager.Callback() {
@Override
public void onStart(MediaProjectionInfo info) {
- Trace.beginSection(
- "SNPC.onProjectionStart");
- // Only enable sensitive content protection if sharing full screen
- // Launch cookie only set (non-null) if sharing single app/task
- updateProjectionState((info.getLaunchCookie() == null) ? info : null);
- Trace.endSection();
+ Trace.beginSection("SNPC.onProjectionStart");
+ try {
+ // Only enable sensitive content protection if sharing full screen
+ // Launch cookie only set (non-null) if sharing single app/task
+ updateProjectionStateAndNotifyListeners(
+ (info.getLaunchCookie() == null) ? info : null);
+ } finally {
+ Trace.endSection();
+ }
}
@Override
public void onStop(MediaProjectionInfo info) {
- Trace.beginSection(
- "SNPC.onProjectionStop");
- updateProjectionState(null);
- Trace.endSection();
- }
-
- private void updateProjectionState(MediaProjectionInfo info) {
- // capture previous state
- boolean wasSensitive = isSensitiveStateActive();
-
- // update internal state
- mProjection = info;
-
- // if either previous or new state is sensitive, notify listeners.
- if (wasSensitive || isSensitiveStateActive()) {
- mListeners.forEach(Runnable::run);
+ Trace.beginSection("SNPC.onProjectionStop");
+ try {
+ updateProjectionStateAndNotifyListeners(null);
+ } finally {
+ Trace.endSection();
}
}
};
@Inject
public SensitiveNotificationProtectionControllerImpl(
+ Context context,
MediaProjectionManager mediaProjectionManager,
- @Main Handler mainHandler) {
- mMediaProjectionManager = mediaProjectionManager;
+ IActivityManager activityManager,
+ @Main Handler mainHandler,
+ @Background Executor bgExecutor) {
+ if (!screenshareNotificationHiding()) {
+ return;
+ }
- if (screenshareNotificationHiding()) {
- mMediaProjectionManager.addCallback(mMediaProjectionCallback, mainHandler);
+ bgExecutor.execute(() -> {
+ ArraySet<String> exemptPackages = new ArraySet<>();
+ // Exempt SystemUI
+ exemptPackages.add(context.getPackageName());
+
+ // Exempt approved bug report handlers
+ try {
+ exemptPackages.addAll(activityManager.getBugreportWhitelistedPackages());
+ } catch (RemoteException e) {
+ Log.e(
+ LOG_TAG,
+ "Error adding bug report handlers to exemption, continuing without",
+ e);
+ // silent failure, skip adding packages to exemption
+ }
+
+ // if currently projecting, notify listeners of exemption changes
+ mainHandler.post(() -> {
+ Trace.beginSection("SNPC.exemptPackagesUpdated");
+ try {
+ updateExemptPackagesAndNotifyListeners(exemptPackages);
+ } finally {
+ Trace.endSection();
+ }
+ });
+ });
+
+ mediaProjectionManager.addCallback(mMediaProjectionCallback, mainHandler);
+ }
+
+ /**
+ * Notify listeners of possible ProjectionState change regardless of current
+ * isSensitiveStateActive value. Method used to ensure updates occur after mExemptPackages gets
+ * updated, which directly changes the outcome of isSensitiveStateActive
+ */
+ @MainThread
+ private void updateExemptPackagesAndNotifyListeners(ArraySet<String> exemptPackages) {
+ Assert.isMainThread();
+ mExemptPackages.addAll(exemptPackages);
+
+ if (mProjection != null) {
+ mListeners.forEach(Runnable::run);
+ }
+ }
+
+ /**
+ * Update ProjectionState respecting current isSensitiveStateActive value. Only notifies
+ * listeners
+ */
+ @MainThread
+ private void updateProjectionStateAndNotifyListeners(MediaProjectionInfo info) {
+ Assert.isMainThread();
+ // capture previous state
+ boolean wasSensitive = isSensitiveStateActive();
+
+ // update internal state
+ mProjection = info;
+
+ // if either previous or new state is sensitive, notify listeners.
+ if (wasSensitive || isSensitiveStateActive()) {
+ mListeners.forEach(Runnable::run);
}
}
@@ -96,11 +163,17 @@
mListeners.remove(onSensitiveStateChanged);
}
+ // TODO(b/323396693): opportunity for optimization
@Override
public boolean isSensitiveStateActive() {
+ MediaProjectionInfo projection = mProjection;
+ if (projection == null) {
+ return false;
+ }
+
// TODO(b/316955558): Add disabled by developer option
- // TODO(b/316955306): Add feature exemption for sysui and bug handlers
- return mProjection != null;
+
+ return !mExemptPackages.contains(projection.getPackageName());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 2acd4b9..139d190 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -111,6 +111,7 @@
// TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
private final List<NotifCallback> mCallbacks = new ArrayList<>();
private final StatusBarWindowCallback mStatusBarWindowCallback;
+ private boolean mPanelExpanded;
/**
* Creates {@link BubblesManager}, returns {@code null} if Optional {@link Bubbles} not present
@@ -242,8 +243,12 @@
// Store callback in a field so it won't get GC'd
mStatusBarWindowCallback =
(keyguardShowing, keyguardOccluded, keyguardGoingAway, bouncerShowing, isDozing,
- panelExpanded, isDreaming) ->
+ panelExpanded, isDreaming) -> {
+ if (panelExpanded != mPanelExpanded) {
+ mPanelExpanded = panelExpanded;
mBubbles.onNotificationPanelExpandedChanged(panelExpanded);
+ }
+ };
notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);
mSysuiProxy = new Bubbles.SysuiProxy() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index da6bfe8..d742da7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -47,7 +47,6 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory;
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -167,9 +166,7 @@
mVibrator,
mAuthRippleController,
mResources,
- KeyguardTransitionInteractorFactory.create(
- TestScopeProvider.getTestScope().getBackgroundScope())
- .getKeyguardTransitionInteractor(),
+ mKosmos.getKeyguardTransitionInteractor(),
KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
mFeatureFlags,
mPrimaryBouncerInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
index fc34255..3f83ce3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
@@ -26,7 +26,7 @@
import com.android.systemui.display.data.repository.fakeDeviceStateRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -47,7 +47,6 @@
@SmallTest
@RunWith(JUnit4::class)
class LogContextInteractorImplTest : SysuiTestCase() {
-
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
private val kosmos = testKosmos()
@@ -64,11 +63,7 @@
LogContextInteractorImpl(
testScope.backgroundScope,
deviceStateRepository,
- KeyguardTransitionInteractorFactory.create(
- repository = keyguardTransitionRepository,
- scope = testScope.backgroundScope,
- )
- .keyguardTransitionInteractor,
+ kosmos.keyguardTransitionInteractor,
udfpsOverlayInteractor,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
index 368d1d9..b28d0c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
@@ -16,71 +16,56 @@
package com.android.systemui.deviceentry.domain.interactor
-import android.app.trust.TrustManager
import android.content.pm.UserInfo
import android.hardware.biometrics.BiometricFaceConstants
import android.hardware.biometrics.BiometricSourceType
-import android.os.Handler
import android.os.PowerManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.keyguard.trustManager
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FaceSensorInfo
-import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
-import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.facePropertyRepository
import com.android.systemui.biometrics.shared.model.LockoutMode
import com.android.systemui.biometrics.shared.model.SensorStrength
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
-import com.android.systemui.bouncer.ui.BouncerView
-import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.FaceWakeUpTriggersConfig
+import com.android.systemui.deviceentry.data.repository.faceWakeUpTriggersConfig
import com.android.systemui.deviceentry.shared.FaceAuthUiEvent
import com.android.systemui.deviceentry.shared.model.ErrorFaceAuthenticationStatus
-import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.data.repository.FakeTrustRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.log.logcatLogBuffer
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
-import com.android.systemui.power.domain.interactor.PowerInteractorFactory
+import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
-import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.testKosmos
import com.android.systemui.user.data.model.SelectionStatus
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestCoroutineScheduler
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.Mock
-import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -89,84 +74,39 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() {
+ val kosmos =
+ testKosmos().apply { this.faceWakeUpTriggersConfig = mock<FaceWakeUpTriggersConfig>() }
private lateinit var underTest: SystemUIDeviceEntryFaceAuthInteractor
- private lateinit var testScope: TestScope
- private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
- private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
- private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
- private lateinit var faceAuthRepository: FakeDeviceEntryFaceAuthRepository
- private lateinit var fakeUserRepository: FakeUserRepository
- private lateinit var facePropertyRepository: FakeFacePropertyRepository
- private lateinit var fakeDeviceEntryFingerprintAuthRepository:
- FakeDeviceEntryFingerprintAuthRepository
- private lateinit var fakeKeyguardRepository: FakeKeyguardRepository
- private lateinit var powerInteractor: PowerInteractor
- private lateinit var fakeBiometricSettingsRepository: FakeBiometricSettingsRepository
+ private val testScope = kosmos.testScope
+ private val bouncerRepository = kosmos.fakeKeyguardBouncerRepository
+ private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ private val keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
+ private val faceAuthRepository = kosmos.fakeDeviceEntryFaceAuthRepository
+ private val fakeUserRepository = kosmos.fakeUserRepository
+ private val facePropertyRepository = kosmos.facePropertyRepository
+ private val fakeDeviceEntryFingerprintAuthRepository =
+ kosmos.fakeDeviceEntryFingerprintAuthRepository
+ private val powerInteractor = kosmos.powerInteractor
+ private val fakeBiometricSettingsRepository = kosmos.fakeBiometricSettingsRepository
- @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock private lateinit var faceWakeUpTriggersConfig: FaceWakeUpTriggersConfig
- @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
- @Mock private lateinit var trustManager: TrustManager
+ private val keyguardUpdateMonitor = kosmos.keyguardUpdateMonitor
+ private val faceWakeUpTriggersConfig = kosmos.faceWakeUpTriggersConfig
+ private val trustManager = kosmos.trustManager
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- val scheduler = TestCoroutineScheduler()
- val dispatcher = StandardTestDispatcher(scheduler)
- testScope = TestScope(dispatcher)
- bouncerRepository = FakeKeyguardBouncerRepository()
- faceAuthRepository = FakeDeviceEntryFaceAuthRepository()
- keyguardTransitionRepository = FakeKeyguardTransitionRepository()
- keyguardTransitionInteractor =
- KeyguardTransitionInteractorFactory.create(
- scope = TestScope().backgroundScope,
- repository = keyguardTransitionRepository,
- )
- .keyguardTransitionInteractor
-
- fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
- fakeUserRepository = FakeUserRepository()
fakeUserRepository.setUserInfos(listOf(primaryUser, secondaryUser))
- facePropertyRepository = FakeFacePropertyRepository()
- fakeKeyguardRepository = FakeKeyguardRepository()
- powerInteractor = PowerInteractorFactory.create().powerInteractor
- fakeBiometricSettingsRepository = FakeBiometricSettingsRepository()
underTest =
SystemUIDeviceEntryFaceAuthInteractor(
mContext,
testScope.backgroundScope,
- dispatcher,
+ kosmos.testDispatcher,
faceAuthRepository,
- {
- PrimaryBouncerInteractor(
- bouncerRepository,
- mock(BouncerView::class.java),
- mock(Handler::class.java),
- mock(KeyguardStateController::class.java),
- mock(KeyguardSecurityModel::class.java),
- mock(PrimaryBouncerCallbackInteractor::class.java),
- mock(FalsingCollector::class.java),
- mock(DismissCallbackRegistry::class.java),
- context,
- keyguardUpdateMonitor,
- FakeTrustRepository(),
- testScope.backgroundScope,
- selectedUserInteractor,
- underTest,
- )
- },
- AlternateBouncerInteractor(
- mock(StatusBarStateController::class.java),
- mock(KeyguardStateController::class.java),
- bouncerRepository,
- FakeFingerprintPropertyRepository(),
- fakeBiometricSettingsRepository,
- FakeSystemClock(),
- keyguardUpdateMonitor,
- testScope.backgroundScope,
- ),
+ { kosmos.primaryBouncerInteractor },
+ kosmos.alternateBouncerInteractor,
keyguardTransitionInteractor,
FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")),
keyguardUpdateMonitor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
index 852f9a5..cf8fe79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
@@ -5,16 +5,16 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
-import com.android.systemui.power.domain.interactor.PowerInteractorFactory
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.utils.GlobalWindowManager
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -36,13 +36,14 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
class ResourceTrimmerTest : SysuiTestCase() {
+ val kosmos = testKosmos()
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
- private val keyguardRepository = FakeKeyguardRepository()
- private val featureFlags = FakeFeatureFlags()
- private val keyguardTransitionRepository = FakeKeyguardTransitionRepository()
- private lateinit var powerInteractor: PowerInteractor
+ private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val featureFlags = kosmos.fakeFeatureFlagsClassic
+ private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ private val powerInteractor = kosmos.powerInteractor
@Mock private lateinit var globalWindowManager: GlobalWindowManager
private lateinit var resourceTrimmer: ResourceTrimmer
@@ -52,7 +53,6 @@
MockitoAnnotations.initMocks(this)
featureFlags.set(Flags.TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK, true)
featureFlags.set(Flags.TRIM_FONT_CACHES_AT_UNLOCK, true)
- powerInteractor = PowerInteractorFactory.create().powerInteractor
keyguardRepository.setDozeAmount(0f)
keyguardRepository.setKeyguardGoingAway(false)
@@ -66,11 +66,7 @@
ResourceTrimmer(
keyguardInteractor,
powerInteractor,
- KeyguardTransitionInteractorFactory.create(
- scope = TestScope().backgroundScope,
- repository = keyguardTransitionRepository,
- )
- .keyguardTransitionInteractor,
+ kosmos.keyguardTransitionInteractor,
globalWindowManager,
testScope.backgroundScope,
testDispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
index e75f557..62855d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -21,16 +21,15 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.DismissAction
import com.android.systemui.keyguard.shared.model.KeyguardDone
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestDispatcher
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -42,11 +41,12 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class KeyguardDismissActionInteractorTest : SysuiTestCase() {
- private lateinit var keyguardRepository: FakeKeyguardRepository
- private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+ val kosmos = testKosmos()
- private lateinit var dispatcher: TestDispatcher
- private lateinit var testScope: TestScope
+ private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
+
+ private val testScope = kosmos.testScope
private lateinit var dismissInteractorWithDependencies:
KeyguardDismissInteractorFactory.WithDependencies
@@ -55,25 +55,18 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- dispatcher = StandardTestDispatcher()
- testScope = TestScope(dispatcher)
dismissInteractorWithDependencies =
KeyguardDismissInteractorFactory.create(
context = context,
testScope = testScope,
+ keyguardRepository = keyguardRepository,
)
- keyguardRepository = dismissInteractorWithDependencies.keyguardRepository
- transitionRepository = FakeKeyguardTransitionRepository()
underTest =
KeyguardDismissActionInteractor(
keyguardRepository,
- KeyguardTransitionInteractorFactory.create(
- scope = testScope.backgroundScope,
- repository = transitionRepository,
- )
- .keyguardTransitionInteractor,
+ kosmos.keyguardTransitionInteractor,
dismissInteractorWithDependencies.interactor,
testScope.backgroundScope,
)
@@ -180,7 +173,7 @@
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GONE,
- testScope
+ testScope,
)
assertThat(executeDismissAction).isNotNull()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt
deleted file mode 100644
index a03aed0..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2023 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.keyguard.domain.interactor
-
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.communal.domain.interactor.CommunalInteractor
-import com.android.systemui.communal.domain.interactor.communalInteractor
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.mock
-import dagger.Lazy
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
-
-open class KeyguardTransitionInteractorTestCase : SysuiTestCase() {
- private val kosmos = testKosmos()
- val testDispatcher = StandardTestDispatcher()
- var testScope = TestScope(testDispatcher)
-
- lateinit var keyguardRepository: FakeKeyguardRepository
- lateinit var transitionRepository: FakeKeyguardTransitionRepository
-
- lateinit var keyguardInteractor: KeyguardInteractor
- lateinit var communalInteractor: CommunalInteractor
- lateinit var transitionInteractor: KeyguardTransitionInteractor
-
- /**
- * Replace these lazy providers with non-null ones if you want test dependencies to use a real
- * instance of the interactor for the test.
- */
- open var fromLockscreenTransitionInteractorLazy: Lazy<FromLockscreenTransitionInteractor>? =
- null
- open var fromPrimaryBouncerTransitionInteractorLazy:
- Lazy<FromPrimaryBouncerTransitionInteractor>? =
- null
-
- open fun setUp() {
- keyguardRepository = FakeKeyguardRepository()
- transitionRepository = FakeKeyguardTransitionRepository()
-
- keyguardInteractor =
- KeyguardInteractorFactory.create(repository = keyguardRepository).keyguardInteractor
-
- communalInteractor = kosmos.communalInteractor
-
- transitionInteractor =
- KeyguardTransitionInteractorFactory.create(
- repository = transitionRepository,
- keyguardInteractor = keyguardInteractor,
- scope = testScope.backgroundScope,
- fromLockscreenTransitionInteractor = fromLockscreenTransitionInteractorLazy
- ?: Lazy { mock() },
- fromPrimaryBouncerTransitionInteractor =
- fromPrimaryBouncerTransitionInteractorLazy ?: Lazy { mock() },
- )
- .also {
- fromLockscreenTransitionInteractorLazy = it.fromLockscreenTransitionInteractor
- fromPrimaryBouncerTransitionInteractorLazy =
- it.fromPrimaryBouncerTransitionInteractor
- }
- .keyguardTransitionInteractor
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index 6eed427..a4483bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -20,76 +20,46 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectValues
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations.initMocks
@SmallTest
@RunWith(AndroidJUnit4::class)
@kotlinx.coroutines.ExperimentalCoroutinesApi
class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
-
- private lateinit var underTest: WindowManagerLockscreenVisibilityInteractor
-
- @Mock private lateinit var surfaceBehindInteractor: KeyguardSurfaceBehindInteractor
- @Mock
- private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
- @Mock
- private lateinit var fromPrimaryBouncerTransitionInteractor:
- FromPrimaryBouncerTransitionInteractor
-
private val lockscreenSurfaceVisibilityFlow = MutableStateFlow<Boolean?>(false)
private val primaryBouncerSurfaceVisibilityFlow = MutableStateFlow<Boolean?>(false)
private val surfaceBehindIsAnimatingFlow = MutableStateFlow(false)
- private val testScope = TestScope()
+ private val kosmos =
+ testKosmos().apply {
+ fromLockscreenTransitionInteractor = mock<FromLockscreenTransitionInteractor>()
+ fromPrimaryBouncerTransitionInteractor = mock<FromPrimaryBouncerTransitionInteractor>()
+ keyguardSurfaceBehindInteractor = mock<KeyguardSurfaceBehindInteractor>()
- private lateinit var keyguardInteractor: KeyguardInteractor
- private lateinit var transitionRepository: FakeKeyguardTransitionRepository
- private lateinit var transitionInteractor: KeyguardTransitionInteractor
+ whenever(fromLockscreenTransitionInteractor.surfaceBehindVisibility)
+ .thenReturn(lockscreenSurfaceVisibilityFlow)
+ whenever(fromPrimaryBouncerTransitionInteractor.surfaceBehindVisibility)
+ .thenReturn(primaryBouncerSurfaceVisibilityFlow)
+ whenever(keyguardSurfaceBehindInteractor.isAnimatingSurface)
+ .thenReturn(surfaceBehindIsAnimatingFlow)
+ }
- @Before
- fun setUp() {
- initMocks(this)
-
- whenever(fromLockscreenTransitionInteractor.surfaceBehindVisibility)
- .thenReturn(lockscreenSurfaceVisibilityFlow)
- whenever(fromPrimaryBouncerTransitionInteractor.surfaceBehindVisibility)
- .thenReturn(primaryBouncerSurfaceVisibilityFlow)
- whenever(surfaceBehindInteractor.isAnimatingSurface)
- .thenReturn(surfaceBehindIsAnimatingFlow)
-
- transitionRepository = FakeKeyguardTransitionRepository()
-
- transitionInteractor =
- KeyguardTransitionInteractorFactory.create(
- scope = testScope.backgroundScope,
- repository = transitionRepository,
- )
- .also { keyguardInteractor = it.keyguardInteractor }
- .keyguardTransitionInteractor
-
- underTest =
- WindowManagerLockscreenVisibilityInteractor(
- keyguardInteractor = keyguardInteractor,
- transitionInteractor = transitionInteractor,
- surfaceBehindInteractor = surfaceBehindInteractor,
- fromLockscreenTransitionInteractor,
- fromPrimaryBouncerTransitionInteractor,
- )
- }
+ private val underTest = kosmos.windowManagerLockscreenVisibilityInteractor
+ private val testScope = kosmos.testScope
+ private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
@Test
fun surfaceBehindVisibility_switchesToCorrectFlow() =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index af38523c..90943de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -46,7 +46,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardLongPressInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
@@ -67,7 +67,6 @@
import com.google.common.truth.Truth.assertThat
import kotlin.math.max
import kotlin.math.min
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -83,7 +82,6 @@
import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
@@ -208,11 +206,7 @@
KeyguardLongPressInteractor(
appContext = mContext,
scope = testScope.backgroundScope,
- transitionInteractor =
- KeyguardTransitionInteractorFactory.create(
- scope = TestScope().backgroundScope,
- )
- .keyguardTransitionInteractor,
+ transitionInteractor = kosmos.keyguardTransitionInteractor,
repository = repository,
logger = UiEventLoggerFake(),
featureFlags = featureFlags,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 310e0b8..f3b9102 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -30,13 +30,12 @@
import com.android.internal.logging.InstanceId
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.keyguard.TestScopeProvider
import com.android.systemui.SysuiTestCase
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.models.player.MediaData
@@ -53,6 +52,7 @@
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.testKosmos
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -93,6 +93,7 @@
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner::class)
class MediaCarouselControllerTest : SysuiTestCase() {
+ val kosmos = testKosmos()
@Mock lateinit var mediaControlPanelFactory: Provider<MediaControlPanel>
@Mock lateinit var panel: MediaControlPanel
@@ -115,7 +116,7 @@
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock lateinit var globalSettings: GlobalSettings
- private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+ private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
@Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
@Captor
lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
@@ -132,7 +133,6 @@
fun setup() {
MockitoAnnotations.initMocks(this)
context.resources.configuration.setLocales(LocaleList(Locale.US, Locale.UK))
- transitionRepository = FakeKeyguardTransitionRepository()
bgExecutor = FakeExecutor(clock)
mediaCarouselController =
MediaCarouselController(
@@ -152,11 +152,7 @@
debugLogger,
mediaFlags,
keyguardUpdateMonitor,
- KeyguardTransitionInteractorFactory.create(
- scope = TestScopeProvider.getTestScope().backgroundScope,
- repository = transitionRepository,
- )
- .keyguardTransitionInteractor,
+ kosmos.keyguardTransitionInteractor,
globalSettings
)
verify(configurationController).addCallback(capture(configListener))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
index e8aa8f0..bbae0c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
@@ -34,7 +34,7 @@
import org.junit.Rule
import org.junit.runner.RunWith
-/** Test for regression b/311121830 */
+/** Test for regression b/311121830 and b/323125376 */
@RunWith(AndroidTestingRunner::class)
@UiThreadTest
@SmallTest
@@ -82,6 +82,55 @@
assertThat(iconView.mLastIcon).isEqualTo(secondState.icon)
}
+ @Test
+ fun alwaysLastIcon_twoStateChanges() {
+ // Need to inflate with the correct theme so the colors can be retrieved and the animations
+ // are run
+ val iconView =
+ AnimateQSIconViewImpl(
+ ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)
+ )
+
+ val initialState =
+ QSTile.State().apply {
+ state = Tile.STATE_ACTIVE
+ icon = QSTileImpl.ResourceIcon.get(WifiIcons.WIFI_FULL_ICONS[4])
+ }
+ val firstState =
+ QSTile.State().apply {
+ state = Tile.STATE_INACTIVE
+ icon = QSTileImpl.ResourceIcon.get(WifiIcons.WIFI_NO_INTERNET_ICONS[4])
+ }
+ val secondState =
+ QSTile.State().apply {
+ state = Tile.STATE_ACTIVE
+ icon = QSTileImpl.ResourceIcon.get(WifiIcons.WIFI_FULL_ICONS[3])
+ }
+ val thirdState =
+ QSTile.State().apply {
+ state = Tile.STATE_INACTIVE
+ icon = QSTileImpl.ResourceIcon.get(WifiIcons.WIFI_NO_NETWORK)
+ }
+
+ // Start with the initial state
+ iconView.setIcon(initialState, /* allowAnimations= */ false)
+
+ // Set the first state to animate, and advance time to one third of the animation
+ iconView.setIcon(firstState, /* allowAnimations= */ true)
+ animatorRule.advanceTimeBy(QSIconViewImpl.QS_ANIM_LENGTH / 3)
+
+ // Set the second state to animate and advance time by another third of animations length
+ iconView.setIcon(secondState, /* allowAnimations= */ true)
+ animatorRule.advanceTimeBy(QSIconViewImpl.QS_ANIM_LENGTH / 3)
+
+ // Set the third state to animate and advance time by two times the animation length
+ // to guarantee that all animations are done
+ iconView.setIcon(thirdState, /* allowAnimations= */ true)
+ animatorRule.advanceTimeBy(QSIconViewImpl.QS_ANIM_LENGTH * 2)
+
+ assertThat(iconView.mLastIcon).isEqualTo(thirdState.icon)
+ }
+
private class AnimateQSIconViewImpl(context: Context) : QSIconViewImpl(context) {
override fun createIcon(): View {
return object : ImageView(context) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 9ce77e5..deecc5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -166,7 +166,7 @@
@Test
public void testLogStopFromNotificationIntent() {
- Intent stopIntent = RecordingService.getNotificationIntent(mContext);
+ Intent stopIntent = mRecordingService.getNotificationIntent(mContext);
mRecordingService.onStartCommand(stopIntent, 0, 0);
// Verify that we log the correct event
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
new file mode 100644
index 0000000..98be163
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 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.policy
+
+import android.app.IActivityManager
+import android.media.projection.MediaProjectionManager
+import android.os.Handler
+import android.platform.test.annotations.DisableFlags
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.server.notification.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@DisableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)
+class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase() {
+ @Mock private lateinit var handler: Handler
+ @Mock private lateinit var activityManager: IActivityManager
+ @Mock private lateinit var mediaProjectionManager: MediaProjectionManager
+ private lateinit var controller: SensitiveNotificationProtectionControllerImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ controller =
+ SensitiveNotificationProtectionControllerImpl(
+ mContext,
+ mediaProjectionManager,
+ activityManager,
+ handler,
+ FakeExecutor(FakeSystemClock())
+ )
+ }
+
+ @Test
+ fun init_noRegisterMediaProjectionManagerCallback() {
+ verifyZeroInteractions(mediaProjectionManager)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
index 9919c6b..a1aff48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
@@ -17,88 +17,93 @@
package com.android.systemui.statusbar.policy
import android.app.ActivityOptions
+import android.app.IActivityManager
import android.app.Notification
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
-import android.os.Handler
+import android.platform.test.annotations.EnableFlags
import android.service.notification.StatusBarNotification
import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.server.notification.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.concurrency.mockExecutorHandler
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.time.FakeSystemClock
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
-import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.mock
-import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+@EnableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)
class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
- @Mock private lateinit var handler: Handler
-
+ @Mock private lateinit var activityManager: IActivityManager
@Mock private lateinit var mediaProjectionManager: MediaProjectionManager
-
@Mock private lateinit var mediaProjectionInfo: MediaProjectionInfo
-
@Mock private lateinit var listener1: Runnable
@Mock private lateinit var listener2: Runnable
@Mock private lateinit var listener3: Runnable
- @Captor
- private lateinit var mediaProjectionCallbackCaptor:
- ArgumentCaptor<MediaProjectionManager.Callback>
-
+ private lateinit var mediaProjectionCallback: MediaProjectionManager.Callback
private lateinit var controller: SensitiveNotificationProtectionControllerImpl
@Before
fun setUp() {
+ allowTestableLooperAsMainThread() // for updating exempt packages and notifying listeners
MockitoAnnotations.initMocks(this)
- mSetFlagsRule.enableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)
setShareFullScreen()
+ whenever(activityManager.bugreportWhitelistedPackages)
+ .thenReturn(listOf(BUGREPORT_PACKAGE_NAME))
- controller = SensitiveNotificationProtectionControllerImpl(mediaProjectionManager, handler)
+ val executor = FakeExecutor(FakeSystemClock())
+
+ controller =
+ SensitiveNotificationProtectionControllerImpl(
+ mContext,
+ mediaProjectionManager,
+ activityManager,
+ mockExecutorHandler(executor),
+ executor
+ )
+
+ // Process exemption processing
+ executor.runAllReady()
// Obtain useful MediaProjectionCallback
- verify(mediaProjectionManager).addCallback(mediaProjectionCallbackCaptor.capture(), any())
+ mediaProjectionCallback = withArgCaptor {
+ verify(mediaProjectionManager).addCallback(capture(), any())
+ }
}
@Test
- fun init_flagEnabled_registerMediaProjectionManagerCallback() {
- assertNotNull(mediaProjectionCallbackCaptor.value)
- }
-
- @Test
- fun init_flagDisabled_noRegisterMediaProjectionManagerCallback() {
- mSetFlagsRule.disableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)
- reset(mediaProjectionManager)
-
- controller = SensitiveNotificationProtectionControllerImpl(mediaProjectionManager, handler)
-
- verifyZeroInteractions(mediaProjectionManager)
+ fun init_registerMediaProjectionManagerCallback() {
+ assertNotNull(mediaProjectionCallback)
}
@Test
fun registerSensitiveStateListener_singleListener() {
controller.registerSensitiveStateListener(listener1)
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
- mediaProjectionCallbackCaptor.value.onStop(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
verify(listener1, times(2)).run()
}
@@ -108,8 +113,8 @@
controller.registerSensitiveStateListener(listener1)
controller.registerSensitiveStateListener(listener2)
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
- mediaProjectionCallbackCaptor.value.onStop(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
verify(listener1, times(2)).run()
verify(listener2, times(2)).run()
@@ -117,12 +122,12 @@
@Test
fun registerSensitiveStateListener_afterProjectionActive() {
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
controller.registerSensitiveStateListener(listener1)
verifyZeroInteractions(listener1)
- mediaProjectionCallbackCaptor.value.onStop(mediaProjectionInfo)
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
verify(listener1).run()
}
@@ -131,15 +136,15 @@
fun unregisterSensitiveStateListener_singleListener() {
controller.registerSensitiveStateListener(listener1)
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
- mediaProjectionCallbackCaptor.value.onStop(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
verify(listener1, times(2)).run()
controller.unregisterSensitiveStateListener(listener1)
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
- mediaProjectionCallbackCaptor.value.onStop(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
verifyNoMoreInteractions(listener1)
}
@@ -150,8 +155,8 @@
controller.registerSensitiveStateListener(listener2)
controller.registerSensitiveStateListener(listener3)
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
- mediaProjectionCallbackCaptor.value.onStop(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
verify(listener1, times(2)).run()
verify(listener2, times(2)).run()
@@ -160,8 +165,8 @@
controller.unregisterSensitiveStateListener(listener1)
controller.unregisterSensitiveStateListener(listener2)
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
- mediaProjectionCallbackCaptor.value.onStop(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
verifyNoMoreInteractions(listener1)
verifyNoMoreInteractions(listener2)
@@ -175,24 +180,24 @@
@Test
fun isSensitiveStateActive_projectionActive_true() {
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
assertTrue(controller.isSensitiveStateActive)
}
@Test
fun isSensitiveStateActive_projectionInactiveAfterActive_false() {
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
- mediaProjectionCallbackCaptor.value.onStop(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
assertFalse(controller.isSensitiveStateActive)
}
@Test
fun isSensitiveStateActive_projectionActiveAfterInactive_true() {
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
- mediaProjectionCallbackCaptor.value.onStop(mediaProjectionInfo)
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
assertTrue(controller.isSensitiveStateActive)
}
@@ -200,7 +205,25 @@
@Test
fun isSensitiveStateActive_projectionActive_singleActivity_false() {
setShareSingleApp()
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ assertFalse(controller.isSensitiveStateActive)
+ }
+
+ @Test
+ fun isSensitiveStateActive_projectionActive_sysuiExempt_false() {
+ // SystemUi context packge name is exempt, but in test scenarios its
+ // com.android.systemui.tests so use that instead of hardcoding
+ whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ assertFalse(controller.isSensitiveStateActive)
+ }
+
+ @Test
+ fun isSensitiveStateActive_projectionActive_bugReportHandlerExempt_false() {
+ whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
assertFalse(controller.isSensitiveStateActive)
}
@@ -215,7 +238,7 @@
@Test
fun shouldProtectNotification_projectionActive_singleActivity_false() {
setShareSingleApp()
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME)
@@ -224,7 +247,7 @@
@Test
fun shouldProtectNotification_projectionActive_fgsNotificationFromProjectionApp_false() {
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
val notificationEntry = setupFgsNotificationEntry(TEST_PROJECTION_PACKAGE_NAME)
@@ -233,7 +256,7 @@
@Test
fun shouldProtectNotification_projectionActive_fgsNotificationNotFromProjectionApp_true() {
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
val notificationEntry = setupFgsNotificationEntry(TEST_PACKAGE_NAME)
@@ -242,21 +265,43 @@
@Test
fun shouldProtectNotification_projectionActive_notFgsNotification_true() {
- mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
val notificationEntry = setupNotificationEntry(TEST_PROJECTION_PACKAGE_NAME)
assertTrue(controller.shouldProtectNotification(notificationEntry))
}
+ @Test
+ fun shouldProtectNotification_projectionActive_sysuiExempt_false() {
+ // SystemUi context packge name is exempt, but in test scenarios its
+ // com.android.systemui.tests so use that instead of hardcoding
+ whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
+
+ assertFalse(controller.shouldProtectNotification(notificationEntry))
+ }
+
+ @Test
+ fun shouldProtectNotification_projectionActive_bugReportHandlerExempt_false() {
+ whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
+
+ assertFalse(controller.shouldProtectNotification(notificationEntry))
+ }
+
private fun setShareFullScreen() {
- `when`(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
- `when`(mediaProjectionInfo.launchCookie).thenReturn(null)
+ whenever(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
+ whenever(mediaProjectionInfo.launchCookie).thenReturn(null)
}
private fun setShareSingleApp() {
- `when`(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
- `when`(mediaProjectionInfo.launchCookie).thenReturn(ActivityOptions.LaunchCookie())
+ whenever(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
+ whenever(mediaProjectionInfo.launchCookie).thenReturn(ActivityOptions.LaunchCookie())
}
private fun setupNotificationEntry(
@@ -266,10 +311,10 @@
val notificationEntry = mock(NotificationEntry::class.java)
val sbn = mock(StatusBarNotification::class.java)
val notification = mock(Notification::class.java)
- `when`(notificationEntry.sbn).thenReturn(sbn)
- `when`(sbn.packageName).thenReturn(packageName)
- `when`(sbn.notification).thenReturn(notification)
- `when`(notification.isFgsOrUij).thenReturn(isFgs)
+ whenever(notificationEntry.sbn).thenReturn(sbn)
+ whenever(sbn.packageName).thenReturn(packageName)
+ whenever(sbn.notification).thenReturn(notification)
+ whenever(notification.isFgsOrUij).thenReturn(isFgs)
return notificationEntry
}
@@ -282,5 +327,6 @@
private const val TEST_PROJECTION_PACKAGE_NAME =
"com.android.systemui.statusbar.policy.projectionpackage"
private const val TEST_PACKAGE_NAME = "com.android.systemui.statusbar.policy.testpackage"
+ private const val BUGREPORT_PACKAGE_NAME = "com.android.test.bugreporthandler"
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/internal/logging/UiEventLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/internal/logging/UiEventLoggerKosmos.kt
index 9059da2..20b9e84 100644
--- a/packages/SystemUI/tests/utils/src/com/android/internal/logging/UiEventLoggerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/internal/logging/UiEventLoggerKosmos.kt
@@ -20,4 +20,4 @@
import com.android.systemui.kosmos.Kosmos
var Kosmos.uiEventLogger: UiEventLogger by Kosmos.Fixture { uiEventLoggerFake }
-val Kosmos.uiEventLoggerFake by Kosmos.Fixture { UiEventLoggerFake() }
+var Kosmos.uiEventLoggerFake by Kosmos.Fixture { UiEventLoggerFake() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/keyguard/logging/ScrimLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/keyguard/logging/ScrimLoggerKosmos.kt
new file mode 100644
index 0000000..901bdcc
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/keyguard/logging/ScrimLoggerKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 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.keyguard.logging
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.scrimLogger by Kosmos.Fixture { mock<ScrimLogger>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt
index 7b36a29..365d97f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt
@@ -35,6 +35,7 @@
FakeFeatureFlagsClassic().apply {
set(Flags.FULL_SCREEN_USER_SWITCHER, false)
set(Flags.NSSL_DEBUG_LINES, false)
+ set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false)
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/LightRevealScrimRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/LightRevealScrimRepositoryKosmos.kt
new file mode 100644
index 0000000..046946e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/LightRevealScrimRepositoryKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.keyguard.data
+
+import com.android.systemui.keyguard.data.repository.FakeLightRevealScrimRepository
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.lightRevealScrimRepository by Kosmos.Fixture { fakeLightRevealScrimRepository }
+
+var Kosmos.fakeLightRevealScrimRepository by Kosmos.Fixture { FakeLightRevealScrimRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
index d9882fc..3b52676 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
@@ -24,7 +24,7 @@
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.shade.data.repository.shadeRepository
-val Kosmos.fromLockscreenTransitionInteractor by
+var Kosmos.fromLockscreenTransitionInteractor by
Kosmos.Fixture {
FromLockscreenTransitionInteractor(
transitionRepository = keyguardTransitionRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
index 719686e..6b76449 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
@@ -26,7 +26,7 @@
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.user.domain.interactor.selectedUserInteractor
-val Kosmos.fromPrimaryBouncerTransitionInteractor by
+var Kosmos.fromPrimaryBouncerTransitionInteractor by
Kosmos.Fixture {
FromPrimaryBouncerTransitionInteractor(
transitionRepository = keyguardTransitionRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt
index 638a6a3..c06f833 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt
@@ -18,12 +18,12 @@
import android.content.applicationContext
import android.view.accessibility.accessibilityManagerWrapper
+import com.android.internal.logging.uiEventLogger
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
-import com.android.systemui.qs.uiEventLogger
val Kosmos.keyguardLongPressInteractor by
Kosmos.Fixture {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorKosmos.kt
index d756f9a61..a646bc6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorKosmos.kt
@@ -20,7 +20,7 @@
import com.android.systemui.keyguard.data.repository.keyguardSurfaceBehindRepository
import com.android.systemui.kosmos.Kosmos
-val Kosmos.keyguardSurfaceBehindInteractor by
+var Kosmos.keyguardSurfaceBehindInteractor by
Kosmos.Fixture {
KeyguardSurfaceBehindInteractor(
repository = keyguardSurfaceBehindRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
deleted file mode 100644
index 5cf656c..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2023 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.keyguard.domain.interactor
-
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.util.mockito.mock
-import dagger.Lazy
-import kotlinx.coroutines.CoroutineScope
-
-/**
- * Helper to create a new KeyguardTransitionInteractor in a way that doesn't require modifying 20+
- * tests whenever we add a constructor param.
- */
-object KeyguardTransitionInteractorFactory {
- @JvmOverloads
- @JvmStatic
- fun create(
- scope: CoroutineScope,
- repository: FakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository(),
- featureFlags: FakeFeatureFlags = FakeFeatureFlagsClassic(),
- keyguardInteractor: KeyguardInteractor =
- KeyguardInteractorFactory.create(featureFlags = featureFlags).keyguardInteractor,
- fromLockscreenTransitionInteractor: Lazy<FromLockscreenTransitionInteractor> = Lazy {
- mock<FromLockscreenTransitionInteractor>()
- },
- fromPrimaryBouncerTransitionInteractor: Lazy<FromPrimaryBouncerTransitionInteractor> =
- Lazy {
- mock<FromPrimaryBouncerTransitionInteractor>()
- },
- ): WithDependencies {
- return WithDependencies(
- repository = repository,
- keyguardInteractor = keyguardInteractor,
- fromLockscreenTransitionInteractor = fromLockscreenTransitionInteractor,
- fromPrimaryBouncerTransitionInteractor = fromPrimaryBouncerTransitionInteractor,
- KeyguardTransitionInteractor(
- scope = scope,
- repository = repository,
- keyguardInteractor = { keyguardInteractor },
- fromLockscreenTransitionInteractor = fromLockscreenTransitionInteractor,
- fromPrimaryBouncerTransitionInteractor = fromPrimaryBouncerTransitionInteractor,
- )
- )
- }
-
- data class WithDependencies(
- val repository: FakeKeyguardTransitionRepository,
- val keyguardInteractor: KeyguardInteractor,
- val fromLockscreenTransitionInteractor: Lazy<FromLockscreenTransitionInteractor>,
- val fromPrimaryBouncerTransitionInteractor: Lazy<FromPrimaryBouncerTransitionInteractor>,
- val keyguardTransitionInteractor: KeyguardTransitionInteractor,
- )
-}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorKosmos.kt
new file mode 100644
index 0000000..58e0a3b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorKosmos.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 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.keyguard.domain.interactor
+
+import com.android.keyguard.logging.scrimLogger
+import com.android.systemui.keyguard.data.lightRevealScrimRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.power.domain.interactor.powerInteractor
+
+val Kosmos.lightRevealScrimInteractor by
+ Kosmos.Fixture {
+ LightRevealScrimInteractor(
+ keyguardTransitionInteractor,
+ lightRevealScrimRepository,
+ applicationCoroutineScope,
+ scrimLogger,
+ powerInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
new file mode 100644
index 0000000..0207280
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.keyguard.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.windowManagerLockscreenVisibilityInteractor by
+ Kosmos.Fixture {
+ WindowManagerLockscreenVisibilityInteractor(
+ keyguardInteractor = keyguardInteractor,
+ transitionInteractor = keyguardTransitionInteractor,
+ surfaceBehindInteractor = keyguardSurfaceBehindInteractor,
+ fromLockscreenInteractor = fromLockscreenTransitionInteractor,
+ fromBouncerInteractor = fromPrimaryBouncerTransitionInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
index 73b7c50..be559ef 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
@@ -16,9 +16,9 @@
package com.android.systemui.plugins.statusbar
+import com.android.internal.logging.uiEventLogger
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.uiEventLogger
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.StatusBarStateControllerImpl
import com.android.systemui.util.mockito.mock
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
index 6332c1a..23d657d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
@@ -16,7 +16,7 @@
package com.android.systemui.qs
-import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.plugins.qs.QSFactory
@@ -24,9 +24,8 @@
val Kosmos.instanceIdSequenceFake: InstanceIdSequenceFake by
Kosmos.Fixture { InstanceIdSequenceFake(0) }
-val Kosmos.uiEventLogger: UiEventLoggerFake by Kosmos.Fixture { UiEventLoggerFake() }
val Kosmos.qsEventLogger: QsEventLoggerFake by
- Kosmos.Fixture { QsEventLoggerFake(uiEventLogger, instanceIdSequenceFake) }
+ Kosmos.Fixture { QsEventLoggerFake(uiEventLoggerFake, instanceIdSequenceFake) }
var Kosmos.newQSTileFactory by Kosmos.Fixture<NewQSTileFactory>()
var Kosmos.qsTileFactory by Kosmos.Fixture<QSFactory>()
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 44682e2..f902439 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -52,6 +52,13 @@
}
flag {
+ name: "fullscreen_fling_gesture"
+ namespace: "accessibility"
+ description: "When true, adds a fling gesture animation for fullscreen magnification"
+ bug: "319175022"
+}
+
+flag {
name: "pinch_zoom_zero_min_span"
namespace: "accessibility"
description: "Whether to set min span of ScaleGestureDetector to zero."
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 805f6e3..351760b 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -25,7 +25,9 @@
import android.accessibilityservice.MagnificationConfig;
import android.animation.Animator;
+import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -51,6 +53,7 @@
import android.view.WindowManager;
import android.view.accessibility.MagnificationAnimationCallback;
import android.view.animation.DecelerateInterpolator;
+import android.widget.Scroller;
import com.android.internal.R;
import com.android.internal.accessibility.common.MagnificationConstants;
@@ -60,6 +63,7 @@
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.AccessibilityTraceManager;
+import com.android.server.accessibility.Flags;
import com.android.server.wm.WindowManagerInternal;
import java.util.ArrayList;
@@ -86,6 +90,8 @@
private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false;
private final Object mLock;
+ private final Supplier<Scroller> mScrollerSupplier;
+ private final Supplier<TimeAnimator> mTimeAnimatorSupplier;
private final ControllerContext mControllerCtx;
@@ -149,7 +155,13 @@
DisplayMagnification(int displayId) {
mDisplayId = displayId;
- mSpecAnimationBridge = new SpecAnimationBridge(mControllerCtx, mLock, mDisplayId);
+ mSpecAnimationBridge =
+ new SpecAnimationBridge(
+ mControllerCtx,
+ mLock,
+ mDisplayId,
+ mScrollerSupplier,
+ mTimeAnimatorSupplier);
}
/**
@@ -406,6 +418,52 @@
}
}
+ void startFlingAnimation(
+ float xPixelsPerSecond,
+ float yPixelsPerSecond,
+ MagnificationAnimationCallback animationCallback
+ ) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG,
+ "startFlingAnimation(spec = " + xPixelsPerSecond + ", animationCallback = "
+ + animationCallback + ")");
+ }
+ if (Thread.currentThread().getId() == mMainThreadId) {
+ mSpecAnimationBridge.startFlingAnimation(
+ xPixelsPerSecond,
+ yPixelsPerSecond,
+ getMinOffsetXLocked(),
+ getMaxOffsetXLocked(),
+ getMinOffsetYLocked(),
+ getMaxOffsetYLocked(),
+ animationCallback);
+ } else {
+ final Message m =
+ PooledLambda.obtainMessage(
+ SpecAnimationBridge::startFlingAnimation,
+ mSpecAnimationBridge,
+ xPixelsPerSecond,
+ yPixelsPerSecond,
+ getMinOffsetXLocked(),
+ getMaxOffsetXLocked(),
+ getMinOffsetYLocked(),
+ getMaxOffsetYLocked(),
+ animationCallback);
+ mControllerCtx.getHandler().sendMessage(m);
+ }
+ }
+
+ void cancelFlingAnimation() {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "cancelFlingAnimation()");
+ }
+ if (Thread.currentThread().getId() == mMainThreadId) {
+ mSpecAnimationBridge.cancelFlingAnimation();
+ } else {
+ mControllerCtx.getHandler().post(mSpecAnimationBridge::cancelFlingAnimation);
+ }
+ }
+
/**
* Get the ID of the last service that changed the magnification spec.
*
@@ -759,6 +817,63 @@
sendSpecToAnimation(mCurrentMagnificationSpec, null);
}
+ @GuardedBy("mLock")
+ void startFling(float xPixelsPerSecond, float yPixelsPerSecond, int id) {
+ if (!mRegistered) {
+ return;
+ }
+ if (!isActivated()) {
+ return;
+ }
+
+ if (id != INVALID_SERVICE_ID) {
+ mIdOfLastServiceToMagnify = id;
+ }
+
+ startFlingAnimation(
+ xPixelsPerSecond,
+ yPixelsPerSecond,
+ new MagnificationAnimationCallback() {
+ @Override
+ public void onResult(boolean success) {
+ // never called
+ }
+
+ @Override
+ public void onResult(boolean success, MagnificationSpec lastSpecSent) {
+ if (DEBUG) {
+ Slog.i(
+ LOG_TAG,
+ "startFlingAnimation finished( "
+ + success
+ + " = "
+ + lastSpecSent.offsetX
+ + ", "
+ + lastSpecSent.offsetY
+ + ")");
+ }
+ synchronized (mLock) {
+ mCurrentMagnificationSpec.setTo(lastSpecSent);
+ onMagnificationChangedLocked();
+ }
+ }
+ });
+ }
+
+
+ @GuardedBy("mLock")
+ void cancelFling(int id) {
+ if (!mRegistered) {
+ return;
+ }
+
+ if (id != INVALID_SERVICE_ID) {
+ mIdOfLastServiceToMagnify = id;
+ }
+
+ cancelFlingAnimation();
+ }
+
boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) {
if (DEBUG) {
Slog.i(LOG_TAG,
@@ -838,7 +953,9 @@
magnificationInfoChangedCallback,
scaleProvider,
/* thumbnailSupplier= */ null,
- backgroundExecutor);
+ backgroundExecutor,
+ () -> new Scroller(context),
+ TimeAnimator::new);
}
/** Constructor for tests */
@@ -849,9 +966,13 @@
@NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback,
@NonNull MagnificationScaleProvider scaleProvider,
Supplier<MagnificationThumbnail> thumbnailSupplier,
- @NonNull Executor backgroundExecutor) {
+ @NonNull Executor backgroundExecutor,
+ Supplier<Scroller> scrollerSupplier,
+ Supplier<TimeAnimator> timeAnimatorSupplier) {
mControllerCtx = ctx;
mLock = lock;
+ mScrollerSupplier = scrollerSupplier;
+ mTimeAnimatorSupplier = timeAnimatorSupplier;
mMainThreadId = mControllerCtx.getContext().getMainLooper().getThread().getId();
mScreenStateObserver = new ScreenStateObserver(mControllerCtx.getContext(), this);
addInfoChangedCallback(magnificationInfoChangedCallback);
@@ -1437,6 +1558,42 @@
}
/**
+ * Call after a pan ends, if the velocity has passed the threshold, to start a fling animation.
+ *
+ * @param displayId The logical display id.
+ * @param xPixelsPerSecond the velocity of the last pan gesture in the X direction, in current
+ * screen pixels per second.
+ * @param yPixelsPerSecond the velocity of the last pan gesture in the Y direction, in current
+ * screen pixels per second.
+ * @param id the ID of the service requesting the change
+ */
+ public void startFling(int displayId, float xPixelsPerSecond, float yPixelsPerSecond, int id) {
+ synchronized (mLock) {
+ final DisplayMagnification display = mDisplays.get(displayId);
+ if (display == null) {
+ return;
+ }
+ display.startFling(xPixelsPerSecond, yPixelsPerSecond, id);
+ }
+ }
+
+ /**
+ * Call to cancel the fling animation if it is running. Call this on any ACTION_DOWN event.
+ *
+ * @param displayId The logical display id.
+ * @param id the ID of the service requesting the change
+ */
+ public void cancelFling(int displayId, int id) {
+ synchronized (mLock) {
+ final DisplayMagnification display = mDisplays.get(displayId);
+ if (display == null) {
+ return;
+ }
+ display.cancelFling(id);
+ }
+ }
+
+ /**
* Get the ID of the last service that changed the magnification spec.
*
* @param displayId The logical display id.
@@ -1698,7 +1855,15 @@
@GuardedBy("mLock")
private boolean mEnabled = false;
- private SpecAnimationBridge(ControllerContext ctx, Object lock, int displayId) {
+ private final Scroller mScroller;
+ private final TimeAnimator mScrollAnimator;
+
+ private SpecAnimationBridge(
+ ControllerContext ctx,
+ Object lock,
+ int displayId,
+ Supplier<Scroller> scrollerSupplier,
+ Supplier<TimeAnimator> timeAnimatorSupplier) {
mControllerCtx = ctx;
mLock = lock;
mDisplayId = displayId;
@@ -1709,6 +1874,37 @@
mValueAnimator.setFloatValues(0.0f, 1.0f);
mValueAnimator.addUpdateListener(this);
mValueAnimator.addListener(this);
+
+ if (Flags.fullscreenFlingGesture()) {
+ mScroller = scrollerSupplier.get();
+ mScrollAnimator = timeAnimatorSupplier.get();
+ mScrollAnimator.addListener(this);
+ mScrollAnimator.setTimeListener(
+ (animation, totalTime, deltaTime) -> {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.v(
+ LOG_TAG,
+ "onScrollAnimationUpdate: "
+ + mEnabled + " : " + totalTime);
+ }
+
+ if (mEnabled) {
+ if (!mScroller.computeScrollOffset()) {
+ animation.end();
+ return;
+ }
+
+ mEndMagnificationSpec.offsetX = mScroller.getCurrX();
+ mEndMagnificationSpec.offsetY = mScroller.getCurrY();
+ setMagnificationSpecLocked(mEndMagnificationSpec);
+ }
+ }
+ });
+ } else {
+ mScroller = null;
+ mScrollAnimator = null;
+ }
}
/**
@@ -1735,16 +1931,20 @@
}
}
- void updateSentSpecMainThread(MagnificationSpec spec,
- MagnificationAnimationCallback animationCallback) {
- if (mValueAnimator.isRunning()) {
- mValueAnimator.cancel();
- }
+ @MainThread
+ void updateSentSpecMainThread(
+ MagnificationSpec spec, MagnificationAnimationCallback animationCallback) {
+ cancelAnimations();
mAnimationCallback = animationCallback;
// If the current and sent specs don't match, update the sent spec.
synchronized (mLock) {
final boolean changed = !mSentMagnificationSpec.equals(spec);
+ if (DEBUG_SET_MAGNIFICATION_SPEC) {
+ Slog.d(
+ LOG_TAG,
+ "updateSentSpecMainThread: " + mEnabled + " : changed: " + changed);
+ }
if (changed) {
if (mAnimationCallback != null) {
animateMagnificationSpecLocked(spec);
@@ -1757,12 +1957,13 @@
}
}
+ @MainThread
private void sendEndCallbackMainThread(boolean success) {
if (mAnimationCallback != null) {
if (DEBUG) {
Slog.d(LOG_TAG, "sendEndCallbackMainThread: " + success);
}
- mAnimationCallback.onResult(success);
+ mAnimationCallback.onResult(success, mSentMagnificationSpec);
mAnimationCallback = null;
}
}
@@ -1830,6 +2031,77 @@
public void onAnimationRepeat(Animator animation) {
}
+
+ /**
+ * Call after a pan ends, if the velocity has passed the threshold, to start a fling
+ * animation.
+ */
+ @MainThread
+ public void startFlingAnimation(
+ float xPixelsPerSecond,
+ float yPixelsPerSecond,
+ float minX,
+ float maxX,
+ float minY,
+ float maxY,
+ MagnificationAnimationCallback animationCallback
+ ) {
+ if (!Flags.fullscreenFlingGesture()) {
+ return;
+ }
+ cancelAnimations();
+
+ mAnimationCallback = animationCallback;
+
+ // We use this as a temp object to send updates every animation frame, so make sure it
+ // matches the current spec before we start.
+ mEndMagnificationSpec.setTo(mSentMagnificationSpec);
+
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "startFlingAnimation: "
+ + "offsetX " + mSentMagnificationSpec.offsetX
+ + "offsetY " + mSentMagnificationSpec.offsetY
+ + "xPixelsPerSecond " + xPixelsPerSecond
+ + "yPixelsPerSecond " + yPixelsPerSecond
+ + "minX " + minX
+ + "maxX " + maxX
+ + "minY " + minY
+ + "maxY " + maxY
+ );
+ }
+
+ mScroller.fling(
+ (int) mSentMagnificationSpec.offsetX,
+ (int) mSentMagnificationSpec.offsetY,
+ (int) xPixelsPerSecond,
+ (int) yPixelsPerSecond,
+ (int) minX,
+ (int) maxX,
+ (int) minY,
+ (int) maxY);
+
+ mScrollAnimator.start();
+ }
+
+ @MainThread
+ void cancelAnimations() {
+ if (mValueAnimator.isRunning()) {
+ mValueAnimator.cancel();
+ }
+
+ cancelFlingAnimation();
+ }
+
+ @MainThread
+ void cancelFlingAnimation() {
+ if (!Flags.fullscreenFlingGesture()) {
+ return;
+ }
+ if (mScrollAnimator.isRunning()) {
+ mScrollAnimator.cancel();
+ }
+ mScroller.forceFinished(true);
+ }
}
private static class ScreenStateObserver extends BroadcastReceiver {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index baae1d93..f4ea754 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -62,6 +62,7 @@
import android.view.MotionEvent.PointerProperties;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
+import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import com.android.internal.R;
@@ -174,6 +175,10 @@
private final boolean mIsWatch;
+ @Nullable private VelocityTracker mVelocityTracker;
+ private final int mMinimumVelocity;
+ private final int mMaximumVelocity;
+
public FullScreenMagnificationGestureHandler(@UiContext Context context,
FullScreenMagnificationController fullScreenMagnificationController,
AccessibilityTraceManager trace,
@@ -184,15 +189,25 @@
@NonNull WindowMagnificationPromptController promptController,
int displayId,
FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper) {
- this(context, fullScreenMagnificationController, trace, callback,
- detectSingleFingerTripleTap, detectTwoFingerTripleTap,
- detectShortcutTrigger, promptController, displayId,
- fullScreenMagnificationVibrationHelper, /* magnificationLogger= */ null);
+ this(
+ context,
+ fullScreenMagnificationController,
+ trace,
+ callback,
+ detectSingleFingerTripleTap,
+ detectTwoFingerTripleTap,
+ detectShortcutTrigger,
+ promptController,
+ displayId,
+ fullScreenMagnificationVibrationHelper,
+ /* magnificationLogger= */ null,
+ ViewConfiguration.get(context));
}
/** Constructor for tests. */
@VisibleForTesting
- FullScreenMagnificationGestureHandler(@UiContext Context context,
+ FullScreenMagnificationGestureHandler(
+ @UiContext Context context,
FullScreenMagnificationController fullScreenMagnificationController,
AccessibilityTraceManager trace,
Callback callback,
@@ -202,7 +217,8 @@
@NonNull WindowMagnificationPromptController promptController,
int displayId,
FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper,
- MagnificationLogger magnificationLogger) {
+ MagnificationLogger magnificationLogger,
+ ViewConfiguration viewConfiguration) {
super(displayId, detectSingleFingerTripleTap, detectTwoFingerTripleTap,
detectShortcutTrigger, trace, callback);
if (DEBUG_ALL) {
@@ -212,6 +228,15 @@
+ ", detectTwoFingerTripleTap = " + detectTwoFingerTripleTap
+ ", detectShortcutTrigger = " + detectShortcutTrigger + ")");
}
+
+ if (Flags.fullscreenFlingGesture()) {
+ mMinimumVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
+ mMaximumVelocity = viewConfiguration.getScaledMaximumFlingVelocity();
+ } else {
+ mMinimumVelocity = 0;
+ mMaximumVelocity = 0;
+ }
+
mFullScreenMagnificationController = fullScreenMagnificationController;
mMagnificationInfoChangedCallback =
new FullScreenMagnificationController.MagnificationInfoChangedCallback() {
@@ -299,6 +324,10 @@
@Override
void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (event.getActionMasked() == ACTION_DOWN) {
+ cancelFling();
+ }
+
handleEventWith(mCurrentState, event, rawEvent, policyFlags);
}
@@ -501,6 +530,7 @@
}
persistScaleAndTransitionTo(mViewportDraggingState);
} else if (action == ACTION_UP || action == ACTION_CANCEL) {
+ onPanningFinished(event);
// if feature flag is enabled, currently only true on watches
if (mIsSinglePanningEnabled) {
mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded();
@@ -578,6 +608,7 @@
Slog.i(mLogTag, "Panned content by scrollX: " + distanceX
+ " scrollY: " + distanceY);
}
+ onPan(second);
mFullScreenMagnificationController.offsetMagnifiedRegion(mDisplayId, distanceX,
distanceY, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
if (mIsSinglePanningEnabled) {
@@ -973,7 +1004,7 @@
&& overscrollState(event, mFirstPointerDownLocation)
== OVERSCROLL_VERTICAL_EDGE) {
transitionToDelegatingStateAndClear();
- }
+ } // TODO(b/319537921): should there be an else here?
//Primary pointer is swiping, so transit to PanningScalingState
transitToPanningScalingStateAndClear();
} else if (mIsSinglePanningEnabled
@@ -982,7 +1013,7 @@
if (overscrollState(event, mFirstPointerDownLocation)
== OVERSCROLL_VERTICAL_EDGE) {
transitionToDelegatingStateAndClear();
- }
+ } // TODO(b/319537921): should there be an else here?
transitToSinglePanningStateAndClear();
} else if (!mIsTwoFingerCountReached) {
// If it is a two-finger gesture, do not transition to the
@@ -1742,6 +1773,71 @@
}
}
+ /** Call during MOVE events for a panning gesture. */
+ private void onPan(MotionEvent event) {
+ if (!Flags.fullscreenFlingGesture()) {
+ return;
+ }
+
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(event);
+ }
+
+ /**
+ * Call during UP events for a panning gesture, so we can detect a fling and play a physics-
+ * based fling animation.
+ */
+ private void onPanningFinished(MotionEvent event) {
+ if (!Flags.fullscreenFlingGesture()) {
+ return;
+ }
+
+ if (mVelocityTracker == null) {
+ Log.e(mLogTag, "onPanningFinished: mVelocityTracker is null");
+ return;
+ }
+ mVelocityTracker.addMovement(event);
+ mVelocityTracker.computeCurrentVelocity(/* units= */ 1000, mMaximumVelocity);
+
+ float xPixelsPerSecond = mVelocityTracker.getXVelocity();
+ float yPixelsPerSecond = mVelocityTracker.getYVelocity();
+
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+
+ if (DEBUG_PANNING_SCALING) {
+ Slog.v(
+ mLogTag,
+ "onPanningFinished: pixelsPerSecond: "
+ + xPixelsPerSecond
+ + ", "
+ + yPixelsPerSecond
+ + " mMinimumVelocity: "
+ + mMinimumVelocity);
+ }
+
+ if ((Math.abs(yPixelsPerSecond) > mMinimumVelocity)
+ || (Math.abs(xPixelsPerSecond) > mMinimumVelocity)) {
+ mFullScreenMagnificationController.startFling(
+ mDisplayId,
+ xPixelsPerSecond,
+ yPixelsPerSecond,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ }
+ }
+
+ private void cancelFling() {
+ if (!Flags.fullscreenFlingGesture()) {
+ return;
+ }
+
+ mFullScreenMagnificationController.cancelFling(
+ mDisplayId,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ }
+
final class SinglePanningState extends SimpleOnGestureListener implements State {
@@ -1756,6 +1852,8 @@
int action = event.getActionMasked();
switch (action) {
case ACTION_UP:
+ onPanningFinished(event);
+ // fall-through!
case ACTION_CANCEL:
mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded();
mOverscrollHandler.clearEdgeState();
@@ -1770,6 +1868,7 @@
if (mCurrentState != mSinglePanningState) {
return true;
}
+ onPan(second);
mFullScreenMagnificationController.offsetMagnifiedRegion(
mDisplayId,
distanceX,
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index 586aa8a..af0777c 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -16,6 +16,8 @@
package com.android.server.companion;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -25,8 +27,10 @@
import android.companion.DevicePresenceEvent;
import android.content.ComponentName;
import android.content.Context;
+import android.hardware.power.Mode;
import android.os.Handler;
import android.os.ParcelUuid;
+import android.os.PowerManagerInternal;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -79,6 +83,8 @@
private final @NonNull CompanionDevicePresenceMonitor mDevicePresenceMonitor;
private final @NonNull CompanionServicesRegister mCompanionServicesRegister;
+ private final PowerManagerInternal mPowerManagerInternal;
+
@GuardedBy("mBoundCompanionApplications")
private final @NonNull AndroidPackageMap<List<CompanionDeviceServiceConnector>>
mBoundCompanionApplications;
@@ -87,11 +93,13 @@
CompanionApplicationController(Context context, AssociationStore associationStore,
ObservableUuidStore observableUuidStore,
- CompanionDevicePresenceMonitor companionDevicePresenceMonitor) {
+ CompanionDevicePresenceMonitor companionDevicePresenceMonitor,
+ PowerManagerInternal powerManagerInternal) {
mContext = context;
mAssociationStore = associationStore;
mObservableUuidStore = observableUuidStore;
mDevicePresenceMonitor = companionDevicePresenceMonitor;
+ mPowerManagerInternal = powerManagerInternal;
mCompanionServicesRegister = new CompanionServicesRegister();
mBoundCompanionApplications = new AndroidPackageMap<>();
mScheduledForRebindingCompanionApplications = new AndroidPackageMap<>();
@@ -364,9 +372,21 @@
boolean isPrimary = serviceConnector.isPrimary();
Slog.i(TAG, "onBinderDied() u" + userId + "/" + packageName + " isPrimary: " + isPrimary);
- // First: Only mark not BOUND for primary service.
- synchronized (mBoundCompanionApplications) {
- if (serviceConnector.isPrimary()) {
+ // First, disable hint mode for Auto profile and mark not BOUND for primary service ONLY.
+ if (isPrimary) {
+ final List<AssociationInfo> associations =
+ mAssociationStore.getAssociationsForPackage(userId, packageName);
+
+ for (AssociationInfo association : associations) {
+ final String deviceProfile = association.getDeviceProfile();
+ if (DEVICE_PROFILE_AUTOMOTIVE_PROJECTION.equals(deviceProfile)) {
+ Slog.i(TAG, "Disable hint mode for device profile: " + deviceProfile);
+ mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, false);
+ break;
+ }
+ }
+
+ synchronized (mBoundCompanionApplications) {
mBoundCompanionApplications.removePackage(userId, packageName);
}
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 5019428..0054bc8 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -20,7 +20,6 @@
import static android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES;
import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES;
import static android.Manifest.permission.MANAGE_COMPANION_DEVICES;
-import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE;
import static android.Manifest.permission.USE_COMPANION_TRANSPORTS;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
@@ -270,7 +269,8 @@
mAssociationStore, mObservableUuidStore, mDevicePresenceCallback);
mCompanionAppController = new CompanionApplicationController(
- context, mAssociationStore, mObservableUuidStore, mDevicePresenceMonitor);
+ context, mAssociationStore, mObservableUuidStore, mDevicePresenceMonitor,
+ mPowerManagerInternal);
mTransportManager = new CompanionTransportManager(context, mAssociationStore);
mSystemDataTransferProcessor = new SystemDataTransferProcessor(this,
mPackageManagerInternal, mAssociationStore,
@@ -1128,7 +1128,9 @@
mDevicePresenceMonitor.onSelfManagedDeviceConnected(associationId);
- if (association.getDeviceProfile() == REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION) {
+ final String deviceProfile = association.getDeviceProfile();
+ if (DEVICE_PROFILE_AUTOMOTIVE_PROJECTION.equals(deviceProfile)) {
+ Slog.i(TAG, "Enable hint mode for device device profile: " + deviceProfile);
mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, true);
}
}
@@ -1146,7 +1148,9 @@
mDevicePresenceMonitor.onSelfManagedDeviceDisconnected(associationId);
- if (association.getDeviceProfile() == REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION) {
+ final String deviceProfile = association.getDeviceProfile();
+ if (DEVICE_PROFILE_AUTOMOTIVE_PROJECTION.equals(deviceProfile)) {
+ Slog.i(TAG, "Disable hint mode for device profile: " + deviceProfile);
mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, false);
}
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 797a2e6..a341b4a 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -1676,7 +1676,7 @@
}
byte[] certificateDigest = null;
try {
- certificateDigest = new Signature(certificateDigestStr).toByteArray();
+ certificateDigest = new Signature(certificateDigestStr.replace(":", "")).toByteArray();
} catch (IllegalArgumentException e) {
Slog.w(TAG, "<" + elementName + "> with invalid sha256-cert-digest in "
+ permFile + " at " + parser.getPositionDescription());
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index e90910a..bd3c8e0 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -155,6 +155,16 @@
{ "exclude-annotation": "androidx.test.filters.FlakyTest" },
{ "exclude-annotation": "org.junit.Ignore" }
]
+ },
+ {
+ "file_patterns": ["Broadcast.*"],
+ "name": "CtsContentTestCases",
+ "options": [
+ { "include-filter": "android.content.cts.BroadcastReceiverTest" },
+ { "exclude-annotation": "androidx.test.filters.LargeTest" },
+ { "exclude-annotation": "androidx.test.filters.FlakyTest" },
+ { "exclude-annotation": "org.junit.Ignore" }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a61199a..7726609 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -170,9 +170,6 @@
private InputMethodManagerInternal mInputMethodManagerInternal;
- // Context cache used for loading pointer resources.
- private Context mPointerIconDisplayContext;
-
private final File mDoubleTouchGestureEnableFile;
private WindowManagerCallbacks mWindowManagerCallbacks;
@@ -416,6 +413,8 @@
new SparseArray<>();
@GuardedBy("mLoadedPointerIconsByDisplayAndType")
boolean mUseLargePointerIcons = false;
+ @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+ final SparseArray<Context> mDisplayContexts = new SparseArray<>();
final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
@Override
@@ -427,6 +426,7 @@
public void onDisplayRemoved(int displayId) {
synchronized (mLoadedPointerIconsByDisplayAndType) {
mLoadedPointerIconsByDisplayAndType.remove(displayId);
+ mDisplayContexts.remove(displayId);
}
}
@@ -440,6 +440,7 @@
return;
}
iconsByType.clear();
+ mDisplayContexts.remove(displayId);
}
mNative.reloadPointerIcons();
}
@@ -1323,11 +1324,6 @@
/** Clean up input window handles of the given display. */
public void onDisplayRemoved(int displayId) {
- if (mPointerIconDisplayContext != null
- && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) {
- mPointerIconDisplayContext = null;
- }
-
updateAdditionalDisplayInputProperties(displayId, AdditionalDisplayInputProperties::reset);
// TODO(b/320763728): Rely on WindowInfosListener to determine when a display has been
@@ -2379,6 +2375,7 @@
synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ }
synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ }
+ synchronized (mLoadedPointerIconsByDisplayAndType) { /* Test if blocked by pointer lock */}
mBatteryController.monitor();
mNative.monitor();
}
@@ -2782,7 +2779,7 @@
}
PointerIcon icon = iconsByType.get(type);
if (icon == null) {
- icon = PointerIcon.getLoadedSystemIcon(getContextForPointerIcon(displayId), type,
+ icon = PointerIcon.getLoadedSystemIcon(getContextForDisplay(displayId), type,
mUseLargePointerIcons);
iconsByType.put(type, icon);
}
@@ -2800,40 +2797,31 @@
return sc.mNativeObject;
}
+ @GuardedBy("mLoadedPointerIconsByDisplayAndType")
@NonNull
- private Context getContextForPointerIcon(int displayId) {
- if (mPointerIconDisplayContext != null
- && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) {
- return mPointerIconDisplayContext;
- }
-
- // Create and cache context for non-default display.
- mPointerIconDisplayContext = getContextForDisplay(displayId);
-
- // Fall back to default display if the requested displayId does not exist.
- if (mPointerIconDisplayContext == null) {
- mPointerIconDisplayContext = getContextForDisplay(Display.DEFAULT_DISPLAY);
- }
- return mPointerIconDisplayContext;
- }
-
- @Nullable
private Context getContextForDisplay(int displayId) {
if (displayId == Display.INVALID_DISPLAY) {
- return null;
+ // Fallback to using the default context.
+ return mContext;
}
- if (mContext.getDisplay().getDisplayId() == displayId) {
+ if (displayId == mContext.getDisplay().getDisplayId()) {
return mContext;
}
- final DisplayManager displayManager = Objects.requireNonNull(
- mContext.getSystemService(DisplayManager.class));
- final Display display = displayManager.getDisplay(displayId);
- if (display == null) {
- return null;
- }
+ Context displayContext = mDisplayContexts.get(displayId);
+ if (displayContext == null) {
+ final DisplayManager displayManager = Objects.requireNonNull(
+ mContext.getSystemService(DisplayManager.class));
+ final Display display = displayManager.getDisplay(displayId);
+ if (display == null) {
+ // Fallback to using the default context.
+ return mContext;
+ }
- return mContext.createDisplayContext(display);
+ displayContext = mContext.createDisplayContext(display);
+ mDisplayContexts.put(displayId, displayContext);
+ }
+ return displayContext;
}
// Native callback.
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 6f75439..35717af 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -691,16 +691,26 @@
TextUtils.formatSimple("Actual total duration (%d) should be greater than 0",
workDuration.getActualTotalDurationNanos()));
}
- if (workDuration.getActualCpuDurationNanos() <= 0) {
+ if (workDuration.getActualCpuDurationNanos() < 0) {
throw new IllegalArgumentException(
- TextUtils.formatSimple("Actual CPU duration (%d) should be greater than 0",
+ TextUtils.formatSimple(
+ "Actual CPU duration (%d) should be greater than or equal to 0",
workDuration.getActualCpuDurationNanos()));
}
if (workDuration.getActualGpuDurationNanos() < 0) {
throw new IllegalArgumentException(
- TextUtils.formatSimple("Actual GPU duration (%d) should be non negative",
+ TextUtils.formatSimple(
+ "Actual GPU duration (%d) should greater than or equal to 0",
workDuration.getActualGpuDurationNanos()));
}
+ if (workDuration.getActualCpuDurationNanos()
+ + workDuration.getActualGpuDurationNanos() <= 0) {
+ throw new IllegalArgumentException(
+ TextUtils.formatSimple(
+ "The actual CPU duration (%d) and the actual GPU duration (%d)"
+ + " should not both be 0", workDuration.getActualCpuDurationNanos(),
+ workDuration.getActualGpuDurationNanos()));
+ }
}
private void onProcStateChanged(boolean updateAllowed) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 8c27bb8..118985a 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -145,7 +145,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -613,8 +612,8 @@
}
private final Context mContext;
- private final AtomicBoolean mIsInitialBinding = new AtomicBoolean(true);
- private final ServiceThread mHandlerThread;
+ private boolean mInitialUserSwitch = true;
+ private ServiceThread mHandlerThread;
private final WindowManagerInternal mWindowManagerInternal;
private final PackageManagerInternal mPackageManagerInternal;
private final IPackageManager mIPackageManager;
@@ -1474,12 +1473,6 @@
public WallpaperManagerService(Context context) {
if (DEBUG) Slog.v(TAG, "WallpaperService startup");
mContext = context;
- if (Flags.bindWallpaperServiceOnItsOwnThreadDuringAUserSwitch()) {
- mHandlerThread = new ServiceThread(TAG, THREAD_PRIORITY_FOREGROUND, true /*allowIo*/);
- mHandlerThread.start();
- } else {
- mHandlerThread = null;
- }
mShuttingDown = false;
mImageWallpaper = ComponentName.unflattenFromString(
context.getResources().getString(R.string.image_wallpaper_component));
@@ -1803,6 +1796,7 @@
switchWallpaper(lockWallpaper, null);
}
switchWallpaper(systemWallpaper, reply);
+ mInitialUserSwitch = false;
}
// Offload color extraction to another thread since switchUser will be called
@@ -3326,11 +3320,8 @@
com.android.internal.R.bool.config_wallpaperTopApp)) {
bindFlags |= Context.BIND_SCHEDULE_LIKE_TOP_APP;
}
- Handler handler = Flags.bindWallpaperServiceOnItsOwnThreadDuringAUserSwitch()
- && !mIsInitialBinding.compareAndSet(true, false)
- ? mHandlerThread.getThreadHandler() : mContext.getMainThreadHandler();
- boolean bindSuccess = mContext.bindServiceAsUser(intent, newConn, bindFlags, handler,
- new UserHandle(serviceUserId));
+ boolean bindSuccess = mContext.bindServiceAsUser(intent, newConn, bindFlags,
+ getHandlerForBindingWallpaperLocked(), new UserHandle(serviceUserId));
if (!bindSuccess) {
String msg = "Unable to bind service: " + componentName;
if (fromUser) {
@@ -3358,6 +3349,20 @@
return true;
}
+ private Handler getHandlerForBindingWallpaperLocked() {
+ if (!Flags.bindWallpaperServiceOnItsOwnThreadDuringAUserSwitch()) {
+ return mContext.getMainThreadHandler();
+ }
+ if (mInitialUserSwitch) {
+ return mContext.getMainThreadHandler();
+ }
+ if (mHandlerThread == null) {
+ mHandlerThread = new ServiceThread(TAG, THREAD_PRIORITY_FOREGROUND, true /*allowIo*/);
+ mHandlerThread.start();
+ }
+ return mHandlerThread.getThreadHandler();
+ }
+
// Updates tracking of the currently bound wallpapers.
private void updateCurrentWallpapers(WallpaperData newWallpaper) {
if (newWallpaper.userId != mCurrentUserId || newWallpaper.equals(mFallbackWallpaper)) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2c2ebe0..7b59759 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -962,6 +962,9 @@
// without security checks
final Binder shareableActivityToken = new Binder();
+ // Token for accessing the initial caller who started the activity.
+ final IBinder initialCallerInfoAccessToken = new Binder();
+
// Tracking cookie for the launch of this activity and it's task.
IBinder mLaunchCookie;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index b7a943b..49df396 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -930,7 +930,8 @@
proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
- r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken);
+ r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken,
+ r.initialCallerInfoAccessToken);
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 0e2d3d1..edf9da1 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -58,6 +58,8 @@
import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
@@ -927,8 +929,7 @@
}
void updateLetterboxSurface(WindowState winHint, Transaction t) {
- final WindowState w = mActivityRecord.findMainWindow();
- if (w != winHint && winHint != null && w != null) {
+ if (shouldNotLayoutLetterbox(winHint)) {
return;
}
layoutLetterbox(winHint);
@@ -937,20 +938,11 @@
}
}
- void layoutLetterbox(WindowState winHint) {
- final WindowState w = mActivityRecord.findMainWindow();
- if (w == null || winHint != null && w != winHint) {
+ void layoutLetterbox(WindowState w) {
+ if (shouldNotLayoutLetterbox(w)) {
return;
}
updateRoundedCornersIfNeeded(w);
- // If there is another main window that is not an application-starting window, we should
- // update rounded corners for it as well, to avoid flickering rounded corners.
- final WindowState nonStartingAppW = mActivityRecord.findMainWindow(
- /* includeStartingApp= */ false);
- if (nonStartingAppW != null && nonStartingAppW != w) {
- updateRoundedCornersIfNeeded(nonStartingAppW);
- }
-
updateWallpaperForLetterbox(w);
if (shouldShowLetterboxUi(w)) {
if (mLetterbox == null) {
@@ -1023,6 +1015,18 @@
return mActivityRecord.getSurfaceControl();
}
+ private static boolean shouldNotLayoutLetterbox(WindowState w) {
+ if (w == null) {
+ return true;
+ }
+ final int type = w.mAttrs.type;
+ // Allow letterbox to be displayed early for base application or application starting
+ // windows even if it is not on the top z order to prevent flickering when the
+ // letterboxed window is brought to the top
+ return (type != TYPE_BASE_APPLICATION && type != TYPE_APPLICATION_STARTING)
+ || w.mAnimatingExit;
+ }
+
private boolean shouldLetterboxHaveRoundedCorners() {
// TODO(b/214030873): remove once background is drawn for transparent activities
// Letterbox shouldn't have rounded corners if the activity is transparent
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index e7aaed4..75409d9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -236,10 +236,6 @@
}).when(mAms).registerUidObserver(any(), anyInt(),
eq(ActivityManager.PROCESS_STATE_TOP), any());
- mConstants.TIMEOUT = 200;
- mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0;
- mConstants.PENDING_COLD_START_CHECK_INTERVAL_MILLIS = 500;
-
final BroadcastHistory emptyHistory = new BroadcastHistory(mConstants) {
public void addBroadcastToHistoryLocked(BroadcastRecord original) {
// Ignored
@@ -259,6 +255,12 @@
mBroadcastQueues[0] = mQueue;
mQueue.start(mContext.getContentResolver());
+
+ // Set the constants after invoking BroadcastQueue.start() to ensure they don't
+ // get overridden by the defaults.
+ mConstants.TIMEOUT = 200;
+ mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0;
+ mConstants.PENDING_COLD_START_CHECK_INTERVAL_MILLIS = 500;
}
@After
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index 52726ca..b224773 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -42,6 +42,7 @@
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import android.accessibilityservice.MagnificationConfig;
+import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -52,11 +53,15 @@
import android.hardware.display.DisplayManagerInternal;
import android.os.Looper;
import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.view.DisplayInfo;
import android.view.MagnificationSpec;
import android.view.accessibility.MagnificationAnimationCallback;
+import android.widget.Scroller;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -65,6 +70,7 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityTraceManager;
+import com.android.server.accessibility.Flags;
import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
@@ -74,6 +80,7 @@
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -104,6 +111,9 @@
static final int INVALID_DISPLAY = 2;
private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
final FullScreenMagnificationController.ControllerContext mMockControllerCtx =
mock(FullScreenMagnificationController.ControllerContext.class);
final Context mMockContext = mock(Context.class);
@@ -118,6 +128,7 @@
private MagnificationScaleProvider mScaleProvider;
private MockContentResolver mResolver;
private final MagnificationThumbnail mMockThumbnail = mock(MagnificationThumbnail.class);
+ private final Scroller mMockScroller = mock(Scroller.class);
private final ArgumentCaptor<MagnificationConfig> mConfigCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
@@ -126,6 +137,8 @@
ValueAnimator.AnimatorUpdateListener mTargetAnimationListener;
ValueAnimator.AnimatorListener mStateListener;
+ private final TimeAnimator mMockTimeAnimator = mock(TimeAnimator.class);
+
FullScreenMagnificationController mFullScreenMagnificationController;
public DisplayManagerInternal mDisplayManagerInternalMock = mock(DisplayManagerInternal.class);
@@ -134,7 +147,8 @@
@Before
public void setUp() {
- Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+ Context realContext = InstrumentationRegistry.getContext();
+ Looper looper = realContext.getMainLooper();
// Pretending ID of the Thread associated with looper as main thread ID in controller
when(mMockContext.getMainLooper()).thenReturn(looper);
when(mMockControllerCtx.getContext()).thenReturn(mMockContext);
@@ -168,7 +182,9 @@
mRequestObserver,
mScaleProvider,
() -> mMockThumbnail,
- ConcurrentUtils.DIRECT_EXECUTOR);
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ () -> mMockScroller,
+ () -> mMockTimeAnimator);
}
@After
@@ -428,7 +444,7 @@
mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
mStateListener.onAnimationEnd(mMockValueAnimator);
verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(endSpec)));
- verify(mAnimationCallback).onResult(true);
+ verify(mAnimationCallback).onResult(eq(true), any());
}
@Test
@@ -451,7 +467,7 @@
mMessageCapturingHandler.sendAllMessages();
verify(mMockValueAnimator, never()).start();
- verify(mAnimationCallback).onResult(true);
+ verify(mAnimationCallback).onResult(eq(true), any());
}
@Test
@@ -653,6 +669,85 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_FULLSCREEN_FLING_GESTURE)
+ public void testStartFling_whileMagnifying_flings() throws InterruptedException {
+ for (int i = 0; i < DISPLAY_COUNT; i++) {
+ startFling_whileMagnifying_flings(i);
+ resetMockWindowManager();
+ }
+ }
+
+ private void startFling_whileMagnifying_flings(int displayId) throws InterruptedException {
+ register(displayId);
+ PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+ float scale = 2.0f;
+ // First zoom in
+ assertTrue(mFullScreenMagnificationController
+ .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, false,
+ SERVICE_ID_1));
+ mMessageCapturingHandler.sendAllMessages();
+
+ PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+ PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
+ mFullScreenMagnificationController.startFling(displayId,
+ /* xPixelsPerSecond= */ 400f,
+ /* yPixelsPerSecond= */ 100f,
+ SERVICE_ID_1
+ );
+ mMessageCapturingHandler.sendAllMessages();
+
+ verify(mMockTimeAnimator).start();
+ verify(mMockScroller).fling(
+ /* startX= */ eq((int) newOffsets.x / 2),
+ /* startY= */ eq((int) newOffsets.y / 2),
+ /* velocityX= */ eq(400),
+ /* velocityY= */ eq(100),
+ /* minX= */ anyInt(),
+ /* minY= */ anyInt(),
+ /* maxX= */ anyInt(),
+ /* maxY= */ anyInt()
+ );
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_FULLSCREEN_FLING_GESTURE)
+ public void testStopFling_whileMagnifyingAndFlinging_stops() throws InterruptedException {
+ for (int i = 0; i < DISPLAY_COUNT; i++) {
+ stopFling_whileMagnifyingAndFlinging_stops(i);
+ resetMockWindowManager();
+ }
+ }
+
+ private void stopFling_whileMagnifyingAndFlinging_stops(int displayId)
+ throws InterruptedException {
+ register(displayId);
+ PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+ float scale = 2.0f;
+ PointF startOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, startCenter, scale);
+ // First zoom in
+ assertTrue(mFullScreenMagnificationController
+ .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, false,
+ SERVICE_ID_1));
+ mMessageCapturingHandler.sendAllMessages();
+
+ mFullScreenMagnificationController.startFling(displayId,
+ /* xPixelsPerSecond= */ 400f,
+ /* yPixelsPerSecond= */ 100f,
+ SERVICE_ID_1
+ );
+ mMessageCapturingHandler.sendAllMessages();
+
+ when(mMockTimeAnimator.isRunning()).thenReturn(true);
+
+ mFullScreenMagnificationController.cancelFling(displayId, SERVICE_ID_1);
+ mMessageCapturingHandler.sendAllMessages();
+
+ verify(mMockTimeAnimator).cancel();
+ // Can't verify forceFinished() because it's final
+// verify(mMockScroller).forceFinished(eq(true));
+ }
+
+ @Test
public void testGetIdOfLastServiceToChange_returnsCorrectValue() {
for (int i = 0; i < DISPLAY_COUNT; i++) {
getIdOfLastServiceToChange_returnsCorrectValue(i);
@@ -736,7 +831,7 @@
verify(mRequestObserver, never()).onFullScreenMagnificationChanged(eq(displayId),
any(Region.class), any(MagnificationConfig.class));
- verify(mAnimationCallback).onResult(true);
+ verify(mAnimationCallback).onResult(eq(true), any());
}
@Test
@@ -772,7 +867,7 @@
mMessageCapturingHandler.sendAllMessages();
// Verify expected actions.
- verify(mAnimationCallback).onResult(false);
+ verify(mAnimationCallback).onResult(eq(false), any());
verify(mMockValueAnimator).start();
verify(mMockValueAnimator).cancel();
@@ -782,7 +877,7 @@
mStateListener.onAnimationEnd(mMockValueAnimator);
checkActivatedAndMagnifying(/* activated= */ false, /* magnifying= */ false, displayId);
- verify(lastAnimationCallback).onResult(true);
+ verify(lastAnimationCallback).onResult(eq(true), any());
}
@Test
@@ -1379,6 +1474,8 @@
private void resetMockWindowManager() {
Mockito.reset(mMockWindowManager);
Mockito.reset(mMockThumbnail);
+ Mockito.reset(mMockScroller);
+ Mockito.reset(mMockTimeAnimator);
initMockWindowManager();
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 71d64cf..8c0d44c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
+import static org.mockito.AdditionalMatchers.gt;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
@@ -40,10 +41,13 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.pm.PackageManager;
@@ -65,6 +69,7 @@
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import android.widget.Scroller;
import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
@@ -79,6 +84,8 @@
import com.android.server.testutils.TestHandler;
import com.android.server.wm.WindowManagerInternal;
+import com.google.common.truth.Truth;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
@@ -186,6 +193,8 @@
@Rule
public final TestableContext mContext = new TestableContext(getInstrumentation().getContext());
+ private final Scroller mMockScroller = spy(new Scroller(mContext));
+
private OffsettableClock mClock;
private FullScreenMagnificationGestureHandler mMgh;
private TestHandler mHandler;
@@ -218,18 +227,21 @@
Settings.Secure.putFloatForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 2.0f,
UserHandle.USER_SYSTEM);
- mFullScreenMagnificationController = new FullScreenMagnificationController(
- mockController,
- new Object(),
- mMagnificationInfoChangedCallback,
- new MagnificationScaleProvider(mContext),
- () -> null,
- ConcurrentUtils.DIRECT_EXECUTOR) {
- @Override
- public boolean magnificationRegionContains(int displayId, float x, float y) {
- return true;
- }
- };
+ mFullScreenMagnificationController =
+ new FullScreenMagnificationController(
+ mockController,
+ new Object(),
+ mMagnificationInfoChangedCallback,
+ new MagnificationScaleProvider(mContext),
+ () -> null,
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ () -> mMockScroller,
+ TimeAnimator::new) {
+ @Override
+ public boolean magnificationRegionContains(int displayId, float x, float y) {
+ return true;
+ }
+ };
doAnswer((Answer<Void>) invocationOnMock -> {
Object[] args = invocationOnMock.getArguments();
@@ -263,11 +275,20 @@
@NonNull
private FullScreenMagnificationGestureHandler newInstance(boolean detectSingleFingerTripleTap,
boolean detectTwoFingerTripleTap, boolean detectShortcutTrigger) {
- FullScreenMagnificationGestureHandler h = new FullScreenMagnificationGestureHandler(
- mContext, mFullScreenMagnificationController, mMockTraceManager, mMockCallback,
- detectSingleFingerTripleTap, detectTwoFingerTripleTap, detectShortcutTrigger,
- mWindowMagnificationPromptController, DISPLAY_0,
- mMockFullScreenMagnificationVibrationHelper, mMockMagnificationLogger);
+ FullScreenMagnificationGestureHandler h =
+ new FullScreenMagnificationGestureHandler(
+ mContext,
+ mFullScreenMagnificationController,
+ mMockTraceManager,
+ mMockCallback,
+ detectSingleFingerTripleTap,
+ detectTwoFingerTripleTap,
+ detectShortcutTrigger,
+ mWindowMagnificationPromptController,
+ DISPLAY_0,
+ mMockFullScreenMagnificationVibrationHelper,
+ mMockMagnificationLogger,
+ ViewConfiguration.get(mContext));
if (isWatch()) {
h.setSinglePanningEnabled(true);
} else {
@@ -724,7 +745,7 @@
//The minimum movement to transit to panningState.
final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
pointer2.offset(sWipeMinDistance + 1, 0);
- send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 1));
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
fastForward(ViewConfiguration.getTapTimeout());
assertIn(STATE_PANNING);
@@ -743,7 +764,7 @@
//The minimum movement to transit to panningState.
final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
pointer2.offset(sWipeMinDistance + 1, 0);
- send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 1));
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
fastForward(ViewConfiguration.getTapTimeout());
assertIn(STATE_PANNING);
@@ -762,7 +783,7 @@
//The minimum movement to transit to panningState.
final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
pointer2.offset(sWipeMinDistance + 1, 0);
- send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 1));
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
assertIn(STATE_PANNING);
returnToNormalFrom(STATE_PANNING);
@@ -780,7 +801,7 @@
//The minimum movement to transit to panningState.
final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
pointer2.offset(sWipeMinDistance + 1, 0);
- send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 1));
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
assertIn(STATE_PANNING);
returnToNormalFrom(STATE_PANNING);
@@ -972,6 +993,198 @@
}
@Test
+ public void singleFinger_testScrollAfterMagnified_startsFling() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
+ goFromStateIdleTo(STATE_ACTIVATED);
+
+ swipeAndHold();
+ fastForward(20);
+ swipe(DEFAULT_POINT, new PointF(DEFAULT_X * 2, DEFAULT_Y * 2), /* durationMs= */ 20);
+
+ verify(mMockScroller).fling(
+ /* startX= */ anyInt(),
+ /* startY= */ anyInt(),
+ // The system fling velocity is configurable and hard to test across devices, so as
+ // long as there is some fling velocity, we are happy.
+ /* velocityX= */ gt(1000),
+ /* velocityY= */ gt(1000),
+ /* minX= */ anyInt(),
+ /* minY= */ anyInt(),
+ /* maxX= */ anyInt(),
+ /* maxY= */ anyInt()
+ );
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_FULLSCREEN_FLING_GESTURE)
+ public void testTwoFingerPanDiagonalAfterMagnified_doesNotFlingXY()
+ throws InterruptedException {
+ goFromStateIdleTo(STATE_ACTIVATED);
+ PointF pointer1 = DEFAULT_POINT;
+ PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+
+ send(downEvent());
+ send(pointerEvent(ACTION_POINTER_DOWN, new PointF[]{pointer1, pointer2}, 1));
+
+ // first move triggers the panning state
+ pointer1.offset(100, 100);
+ pointer2.offset(100, 100);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[]{pointer1, pointer2}, 0));
+
+ // second move actually pans
+ pointer1.offset(100, 100);
+ pointer2.offset(100, 100);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[]{pointer1, pointer2}, 0));
+ pointer1.offset(100, 100);
+ pointer2.offset(100, 100);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[]{pointer1, pointer2}, 0));
+
+ assertIn(STATE_PANNING);
+ mHandler.timeAdvance();
+ returnToNormalFrom(STATE_PANNING);
+
+ mHandler.timeAdvance();
+
+ verifyNoMoreInteractions(mMockScroller);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_FULLSCREEN_FLING_GESTURE)
+ public void testTwoFingerPanDiagonalAfterMagnified_startsFlingXY()
+ throws InterruptedException {
+ goFromStateIdleTo(STATE_ACTIVATED);
+ PointF pointer1 = DEFAULT_POINT;
+ PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+
+ send(downEvent());
+ send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
+
+ // first move triggers the panning state
+ pointer1.offset(100, 100);
+ pointer2.offset(100, 100);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
+
+ // second move actually pans
+ pointer1.offset(100, 100);
+ pointer2.offset(100, 100);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
+ pointer1.offset(100, 100);
+ pointer2.offset(100, 100);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
+
+ assertIn(STATE_PANNING);
+ mHandler.timeAdvance();
+ returnToNormalFrom(STATE_PANNING);
+
+ mHandler.timeAdvance();
+
+ verify(mMockScroller).fling(
+ /* startX= */ anyInt(),
+ /* startY= */ anyInt(),
+ // The system fling velocity is configurable and hard to test across devices, so as
+ // long as there is some fling velocity, we are happy.
+ /* velocityX= */ gt(1000),
+ /* velocityY= */ gt(1000),
+ /* minX= */ anyInt(),
+ /* minY= */ anyInt(),
+ /* maxX= */ anyInt(),
+ /* maxY= */ anyInt()
+ );
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_FULLSCREEN_FLING_GESTURE)
+ public void testTwoFingerPanRightAfterMagnified_startsFlingXOnly()
+ throws InterruptedException {
+ goFromStateIdleTo(STATE_ACTIVATED);
+ PointF pointer1 = DEFAULT_POINT;
+ PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+
+ send(downEvent());
+ send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
+
+ // first move triggers the panning state
+ pointer1.offset(100, 0);
+ pointer2.offset(100, 0);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
+
+ // second move actually pans
+ pointer1.offset(100, 0);
+ pointer2.offset(100, 0);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
+ pointer1.offset(100, 0);
+ pointer2.offset(100, 0);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
+
+ assertIn(STATE_PANNING);
+ mHandler.timeAdvance();
+ returnToNormalFrom(STATE_PANNING);
+
+ mHandler.timeAdvance();
+
+ verify(mMockScroller).fling(
+ /* startX= */ anyInt(),
+ /* startY= */ anyInt(),
+ // The system fling velocity is configurable and hard to test across devices, so as
+ // long as there is some fling velocity, we are happy.
+ /* velocityX= */ gt(100),
+ /* velocityY= */ eq(0),
+ /* minX= */ anyInt(),
+ /* minY= */ anyInt(),
+ /* maxX= */ anyInt(),
+ /* maxY= */ anyInt()
+ );
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_FULLSCREEN_FLING_GESTURE)
+ public void testDownEvent_cancelsFling()
+ throws InterruptedException {
+ goFromStateIdleTo(STATE_ACTIVATED);
+ PointF pointer1 = DEFAULT_POINT;
+ PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+
+ send(downEvent());
+ send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
+
+ // first move triggers the panning state
+ pointer1.offset(100, 0);
+ pointer2.offset(100, 0);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
+
+ // second move actually pans
+ pointer1.offset(100, 0);
+ pointer2.offset(100, 0);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
+ pointer1.offset(100, 0);
+ pointer2.offset(100, 0);
+ fastForward(20);
+ send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
+
+ assertIn(STATE_PANNING);
+ mHandler.timeAdvance();
+ returnToNormalFrom(STATE_PANNING);
+
+ mHandler.timeAdvance();
+
+ send(downEvent());
+ mHandler.timeAdvance();
+
+ verify(mMockScroller).forceFinished(eq(true));
+ }
+
+ @Test
public void testShortcutTriggered_invokeShowWindowPromptAction() {
goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED);
@@ -1397,8 +1610,11 @@
send(upEvent());
}
- private void swipe(PointF start, PointF end) {
- swipeAndHold(start, end);
+ private void swipe(PointF start, PointF end, int durationMs) {
+ var mid = new PointF(start.x + (end.x - start.x) / 2f, start.y + (end.y - start.y) / 2f);
+ swipeAndHold(start, mid);
+ fastForward(durationMs);
+ send(moveEvent(end.x - start.x / 10f, end.y - start.y / 10f));
send(upEvent(end.x, end.y));
}
@@ -1491,9 +1707,18 @@
private MotionEvent pointerEvent(int action, float x, float y) {
- return pointerEvent(action, new PointF[] {DEFAULT_POINT, new PointF(x, y)}, 1);
+ return pointerEvent(action, new PointF[] {DEFAULT_POINT, new PointF(x, y)},
+ (action == ACTION_POINTER_UP || action == ACTION_POINTER_DOWN) ? 1 : 0);
}
+ /**
+ * Create a pointer event simulating the given pointer positions.
+ *
+ * @param action the action
+ * @param pointersPosition positions of the pointers
+ * @param changedIndex the index of the pointer associated with the ACTION_POINTER_UP or
+ * ACTION_POINTER_DOWN action. Must be 0 for all other actions.
+ */
private MotionEvent pointerEvent(int action, PointF[] pointersPosition, int changedIndex) {
final MotionEvent.PointerProperties[] PointerPropertiesArray =
new MotionEvent.PointerProperties[pointersPosition.length];
@@ -1513,12 +1738,12 @@
pointerCoordsArray[i] = pointerCoords;
}
- action += (changedIndex << ACTION_POINTER_INDEX_SHIFT);
+ var actionWithPointer = action | (changedIndex << ACTION_POINTER_INDEX_SHIFT);
- return MotionEvent.obtain(
+ var event = MotionEvent.obtain(
/* downTime */ mClock.now(),
/* eventTime */ mClock.now(),
- /* action */ action,
+ /* action */ actionWithPointer,
/* pointerCount */ pointersPosition.length,
/* pointerProperties */ PointerPropertiesArray,
/* pointerCoords */ pointerCoordsArray,
@@ -1530,6 +1755,14 @@
/* edgeFlags */ 0,
/* source */ InputDevice.SOURCE_TOUCHSCREEN,
/* flags */ 0);
+
+ Truth.assertThat(event.getActionIndex()).isEqualTo(changedIndex);
+ Truth.assertThat(event.getActionMasked()).isEqualTo(action);
+ if (action == ACTION_DOWN) {
+ Truth.assertThat(changedIndex).isEqualTo(0);
+ }
+
+ return event;
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 28d07f9..cd904eb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -42,6 +42,7 @@
import static org.mockito.Mockito.when;
import android.accessibilityservice.MagnificationConfig;
+import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -59,6 +60,7 @@
import android.view.DisplayInfo;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.MagnificationAnimationCallback;
+import android.widget.Scroller;
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
@@ -119,6 +121,8 @@
@Mock
private ValueAnimator mValueAnimator;
@Mock
+ private TimeAnimator mTimeAnimator;
+ @Mock
private MessageCapturingHandler mMessageCapturingHandler;
private FullScreenMagnificationController mScreenMagnificationController;
@@ -195,14 +199,17 @@
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternal);
- mScreenMagnificationController = spy(new FullScreenMagnificationController(
- mControllerCtx,
- new Object(),
- mScreenMagnificationInfoChangedCallbackDelegate,
- mScaleProvider,
- () -> null,
- ConcurrentUtils.DIRECT_EXECUTOR
- ));
+ mScreenMagnificationController =
+ spy(
+ new FullScreenMagnificationController(
+ mControllerCtx,
+ new Object(),
+ mScreenMagnificationInfoChangedCallbackDelegate,
+ mScaleProvider,
+ () -> null,
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ () -> new Scroller(mContext),
+ () -> mTimeAnimator));
mScreenMagnificationController.register(TEST_DISPLAY);
mMagnificationConnectionManager = spy(
diff --git a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
index ffb3bce..4ab9d3e 100644
--- a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -90,10 +90,12 @@
private static final long[] DURATIONS_ZERO = new long[] {};
private static final long[] TIMESTAMPS_ZERO = new long[] {};
private static final long[] TIMESTAMPS_TWO = new long[] {1L, 2L};
- private static final WorkDuration[] WORK_DURATIONS_THREE = new WorkDuration[] {
+ private static final WorkDuration[] WORK_DURATIONS_FIVE = new WorkDuration[] {
new WorkDuration(1L, 11L, 8L, 4L, 1L),
new WorkDuration(2L, 13L, 8L, 6L, 2L),
new WorkDuration(3L, 333333333L, 8L, 333333333L, 3L),
+ new WorkDuration(2L, 13L, 0L, 6L, 2L),
+ new WorkDuration(2L, 13L, 8L, 0L, 2L),
};
@Mock private Context mContext;
@@ -609,9 +611,9 @@
.createHintSession(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
a.updateTargetWorkDuration(100L);
- a.reportActualWorkDuration2(WORK_DURATIONS_THREE);
+ a.reportActualWorkDuration2(WORK_DURATIONS_FIVE);
verify(mNativeWrapperMock, times(1)).halReportActualWorkDuration(anyLong(),
- eq(WORK_DURATIONS_THREE));
+ eq(WORK_DURATIONS_FIVE));
assertThrows(IllegalArgumentException.class, () -> {
a.reportActualWorkDuration2(new WorkDuration[] {});
@@ -627,7 +629,7 @@
});
assertThrows(IllegalArgumentException.class, () -> {
- a.reportActualWorkDuration2(new WorkDuration[] {new WorkDuration(1L, 11L, 0L, 4L, 1L)});
+ a.reportActualWorkDuration2(new WorkDuration[] {new WorkDuration(1L, 11L, 0L, 0L, 1L)});
});
assertThrows(IllegalArgumentException.class, () -> {
@@ -648,7 +650,7 @@
latch.await();
assertFalse(service.mUidObserver.isUidForeground(a.mUid));
- a.reportActualWorkDuration2(WORK_DURATIONS_THREE);
+ a.reportActualWorkDuration2(WORK_DURATIONS_FIVE);
verify(mNativeWrapperMock, never()).halReportActualWorkDuration(anyLong(), any(), any());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 03cdbbd..eddff9ab 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -716,7 +716,8 @@
String certificateDigestStr = "E9:7A:BC:2C:D1:CA:8D:58:6A:57:0B:8C:F8:60:AA:D2:"
+ "8D:13:30:2A:FB:C9:00:2C:5D:53:B2:6C:09:A4:85:A0";
- byte[] certificateDigest = new Signature(certificateDigestStr).toByteArray();
+ byte[] certificateDigest = new Signature(certificateDigestStr.replace(":", ""))
+ .toByteArray();
String contents = "<config>"
+ "<" + "enhanced-confirmation-trusted-installer" + " "
+ "package=\"" + pkgName + "\""
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 0c1a9c3..f42cdb8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -845,6 +845,30 @@
}
@Test
+ public void testLetterboxDisplayedForWindowBelow() {
+ setUpDisplaySizeWithApp(1000, 2500);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+ // Prepare two windows, one base app window below the splash screen
+ final WindowState appWindow = addWindowToActivity(mActivity);
+ final WindowState startWindow = addWindowToActivity(mActivity, TYPE_APPLICATION_STARTING);
+ spyOn(appWindow);
+ // Base app window is letterboxed for display cutout and splash screen is fullscreen
+ doReturn(true).when(appWindow).isLetterboxedForDisplayCutout();
+
+ mActivity.mRootWindowContainer.performSurfacePlacement();
+
+ assertEquals(2, mActivity.mChildren.size());
+ // Splash screen is still the activity's main window
+ assertEquals(startWindow, mActivity.findMainWindow());
+ assertFalse(startWindow.isLetterboxedForDisplayCutout());
+
+ final Rect letterboxInnerBounds = new Rect();
+ mActivity.getLetterboxInnerBounds(letterboxInnerBounds);
+ // Letterboxed is still displayed for app window below splash screen
+ assertFalse(letterboxInnerBounds.isEmpty());
+ }
+
+ @Test
public void testLetterboxFullscreenBoundsAndNotImeAttachable() {
final int displayWidth = 2500;
setUpDisplaySizeWithApp(displayWidth, 1000);
@@ -4773,8 +4797,12 @@
}
private WindowState addWindowToActivity(ActivityRecord activity) {
+ return addWindowToActivity(activity, WindowManager.LayoutParams.TYPE_BASE_APPLICATION);
+ }
+
+ private WindowState addWindowToActivity(ActivityRecord activity, int type) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
- params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+ params.type = type;
params.setFitInsetsSides(0);
params.setFitInsetsTypes(0);
final TestWindowState w = new TestWindowState(
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 536e458..01448c3 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -17,6 +17,7 @@
package android.telecom;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -43,6 +44,7 @@
import com.android.internal.telecom.IConnectionService;
import com.android.internal.telecom.IConnectionServiceAdapter;
import com.android.internal.telecom.RemoteServiceCallback;
+import com.android.server.telecom.flags.Flags;
import java.util.ArrayList;
import java.util.Collection;
@@ -3235,27 +3237,27 @@
}
/**
- * Called after the {@link Connection} returned by
+ * Called by Telecom after the {@link Connection} returned by
* {@link #onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}
* or {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)} has been
* added to the {@link ConnectionService} and sent to Telecom.
*
- * @param connection the {@link Connection}.
- * @hide
+ * @param connection the {@link Connection} which was added to Telecom.
*/
- public void onCreateConnectionComplete(Connection connection) {
+ @FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES)
+ public void onCreateConnectionComplete(@NonNull Connection connection) {
}
/**
- * Called after the {@link Conference} returned by
+ * Called by Telecom after the {@link Conference} returned by
* {@link #onCreateIncomingConference(PhoneAccountHandle, ConnectionRequest)}
* or {@link #onCreateOutgoingConference(PhoneAccountHandle, ConnectionRequest)} has been
* added to the {@link ConnectionService} and sent to Telecom.
*
- * @param conference the {@link Conference}.
- * @hide
+ * @param conference the {@link Conference} which was added to Telecom.
*/
- public void onCreateConferenceComplete(Conference conference) {
+ @FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES)
+ public void onCreateConferenceComplete(@NonNull Conference conference) {
}
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
index 2b0d626..d5db612 100644
--- a/telephony/java/android/telephony/CarrierRestrictionRules.java
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -174,6 +174,7 @@
private int mMultiSimPolicy;
@CarrierRestrictionStatus
private int mCarrierRestrictionStatus;
+ private boolean mUseCarrierLockInfo;
private CarrierRestrictionRules() {
mAllowedCarriers = new ArrayList<CarrierIdentifier>();
@@ -183,6 +184,7 @@
mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED;
mMultiSimPolicy = MULTISIM_POLICY_NONE;
mCarrierRestrictionStatus = TelephonyManager.CARRIER_RESTRICTION_STATUS_UNKNOWN;
+ mUseCarrierLockInfo = false;
}
private CarrierRestrictionRules(Parcel in) {
@@ -198,6 +200,7 @@
if (Flags.carrierRestrictionRulesEnhancement()) {
in.readTypedList(mAllowedCarrierInfo, CarrierInfo.CREATOR);
in.readTypedList(mExcludedCarrierInfo, CarrierInfo.CREATOR);
+ mUseCarrierLockInfo = in.readBoolean();
}
}
@@ -213,6 +216,14 @@
* Indicates if all carriers are allowed
*/
public boolean isAllCarriersAllowed() {
+ if (Flags.carrierRestrictionStatus() && mCarrierRestrictionStatus
+ == TelephonyManager.CARRIER_RESTRICTION_STATUS_NOT_RESTRICTED) {
+ return true;
+ }
+ if (Flags.carrierRestrictionRulesEnhancement() && mUseCarrierLockInfo) {
+ return (mAllowedCarrierInfo.isEmpty() && mExcludedCarrierInfo.isEmpty()
+ && mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_ALLOWED);
+ }
return (mAllowedCarriers.isEmpty() && mExcludedCarriers.isEmpty()
&& mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_ALLOWED);
}
@@ -419,6 +430,7 @@
if (Flags.carrierRestrictionRulesEnhancement()) {
out.writeTypedList(mAllowedCarrierInfo);
out.writeTypedList(mExcludedCarrierInfo);
+ out.writeBoolean(mUseCarrierLockInfo);
}
}
@@ -451,7 +463,8 @@
public String toString() {
return "CarrierRestrictionRules(allowed:" + mAllowedCarriers + ", excluded:"
+ mExcludedCarriers + ", default:" + mCarrierRestrictionDefault
- + ", multisim policy:" + mMultiSimPolicy + getCarrierInfoList() + ")";
+ + ", MultiSim policy:" + mMultiSimPolicy + getCarrierInfoList() +
+ " mIsCarrierLockInfoSupported = " + mUseCarrierLockInfo + ")";
}
private String getCarrierInfoList() {
@@ -490,6 +503,7 @@
TelephonyManager.CARRIER_RESTRICTION_STATUS_NOT_RESTRICTED;
mRules.mAllowedCarrierInfo.clear();
mRules.mExcludedCarrierInfo.clear();
+ mRules.mUseCarrierLockInfo = false;
}
return this;
}
@@ -572,5 +586,16 @@
mRules.mExcludedCarrierInfo = new ArrayList<CarrierInfo>(excludedCarrierInfo);
return this;
}
+
+ /**
+ * set whether the HAL radio supports the advanced carrier lock features or not.
+ *
+ * @param carrierLockInfoSupported advanced carrierInfo changes supported or not
+ * @hide
+ */
+ public @NonNull Builder setCarrierLockInfoFeature(boolean carrierLockInfoSupported) {
+ mRules.mUseCarrierLockInfo = carrierLockInfoSupported;
+ return this;
+ }
}
}
diff --git a/tools/codegen/src/com/android/codegen/FileInfo.kt b/tools/codegen/src/com/android/codegen/FileInfo.kt
index a1d0389..cc3a156 100644
--- a/tools/codegen/src/com/android/codegen/FileInfo.kt
+++ b/tools/codegen/src/com/android/codegen/FileInfo.kt
@@ -238,7 +238,7 @@
} else if (classBounds.isDataclass) {
// Insert placeholder for generated code to be inserted for the 1st time
- chunks.last = (chunks.last as Code)
+ chunks[chunks.lastIndex] = (chunks.last() as Code)
.lines
.dropLastWhile { it.isBlank() }
.run {
@@ -286,4 +286,4 @@
.let { addAll(it) }
}
}
-}
\ No newline at end of file
+}
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
index 9ceb204..a40bdd7 100644
--- a/tools/codegen/src/com/android/codegen/Utils.kt
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -137,14 +137,4 @@
cause)
}
-var <T> MutableList<T>.last
- get() = last()
- set(value) {
- if (isEmpty()) {
- add(value)
- } else {
- this[size - 1] = value
- }
- }
-
-inline fun <T> buildList(init: MutableList<T>.() -> Unit) = mutableListOf<T>().apply(init)
\ No newline at end of file
+inline fun <T> buildList(init: MutableList<T>.() -> Unit) = mutableListOf<T>().apply(init)