Merge "Add another namespace to mapper." into main
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 06e86af..78248d9 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -138,7 +138,8 @@
new LocalDataShareAdapterResourceManager();
private Handler mHandler;
- private IContentCaptureServiceCallback mCallback;
+ @Nullable private IContentCaptureServiceCallback mContentCaptureServiceCallback;
+ @Nullable private IContentProtectionAllowlistCallback mContentProtectionAllowlistCallback;
private long mCallerMismatchTimeout = 1000;
private long mLastCallerMismatchLog;
@@ -215,6 +216,16 @@
Binder.getCallingUid(),
events));
}
+
+ @Override
+ public void onUpdateAllowlistRequest(IBinder callback) {
+ mHandler.sendMessage(
+ obtainMessage(
+ ContentCaptureService::handleOnUpdateAllowlistRequest,
+ ContentCaptureService.this,
+ Binder.getCallingUid(),
+ callback));
+ }
};
/** Binder that receives calls from the app in the content capture flow. */
@@ -278,14 +289,31 @@
*/
public final void setContentCaptureWhitelist(@Nullable Set<String> packages,
@Nullable Set<ComponentName> activities) {
- final IContentCaptureServiceCallback callback = mCallback;
- if (callback == null) {
- Log.w(TAG, "setContentCaptureWhitelist(): no server callback");
+
+ IContentCaptureServiceCallback contentCaptureCallback = mContentCaptureServiceCallback;
+ IContentProtectionAllowlistCallback contentProtectionAllowlistCallback =
+ mContentProtectionAllowlistCallback;
+
+ if (contentCaptureCallback == null && contentProtectionAllowlistCallback == null) {
+ Log.w(TAG, "setContentCaptureWhitelist(): missing both server callbacks");
+ return;
+ }
+
+ if (contentCaptureCallback != null) {
+ if (contentProtectionAllowlistCallback != null) {
+ throw new IllegalStateException("Have both server callbacks");
+ }
+ try {
+ contentCaptureCallback.setContentCaptureWhitelist(
+ toList(packages), toList(activities));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
return;
}
try {
- callback.setContentCaptureWhitelist(toList(packages), toList(activities));
+ contentProtectionAllowlistCallback.setAllowlist(toList(packages));
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -314,7 +342,7 @@
*/
public final void setContentCaptureConditions(@NonNull String packageName,
@Nullable Set<ContentCaptureCondition> conditions) {
- final IContentCaptureServiceCallback callback = mCallback;
+ final IContentCaptureServiceCallback callback = mContentCaptureServiceCallback;
if (callback == null) {
Log.w(TAG, "setContentCaptureConditions(): no server callback");
return;
@@ -425,7 +453,7 @@
public final void disableSelf() {
if (sDebug) Log.d(TAG, "disableSelf()");
- final IContentCaptureServiceCallback callback = mCallback;
+ final IContentCaptureServiceCallback callback = mContentCaptureServiceCallback;
if (callback == null) {
Log.w(TAG, "disableSelf(): no server callback");
return;
@@ -464,13 +492,14 @@
}
private void handleOnConnected(@NonNull IBinder callback) {
- mCallback = IContentCaptureServiceCallback.Stub.asInterface(callback);
+ mContentCaptureServiceCallback = IContentCaptureServiceCallback.Stub.asInterface(callback);
onConnected();
}
private void handleOnDisconnected() {
onDisconnected();
- mCallback = null;
+ mContentCaptureServiceCallback = null;
+ mContentProtectionAllowlistCallback = null;
}
//TODO(b/111276913): consider caching the InteractionSessionId for the lifetime of the session,
@@ -583,6 +612,16 @@
onContentCaptureEvent(sessionId, endEvent);
}
+ private void handleOnUpdateAllowlistRequest(int uid, @NonNull IBinder callback) {
+ if (uid != Process.SYSTEM_UID) {
+ Log.e(TAG, "handleOnUpdateAllowlistRequest() not allowed for uid: " + uid);
+ return;
+ }
+ mContentProtectionAllowlistCallback =
+ IContentProtectionAllowlistCallback.Stub.asInterface(callback);
+ onConnected();
+ }
+
private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) {
onActivitySnapshot(new ContentCaptureSessionId(sessionId), snapshotData);
}
@@ -701,13 +740,14 @@
private void writeFlushMetrics(int sessionId, @Nullable ComponentName app,
@NonNull FlushMetrics flushMetrics, @Nullable ContentCaptureOptions options,
int flushReason) {
- if (mCallback == null) {
+ if (mContentCaptureServiceCallback == null) {
Log.w(TAG, "writeSessionFlush(): no server callback");
return;
}
try {
- mCallback.writeSessionFlush(sessionId, app, flushMetrics, options, flushReason);
+ mContentCaptureServiceCallback.writeSessionFlush(
+ sessionId, app, flushMetrics, options, flushReason);
} catch (RemoteException e) {
Log.e(TAG, "failed to write flush metrics: " + e);
}
diff --git a/core/java/android/service/contentcapture/IContentProtectionAllowlistCallback.aidl b/core/java/android/service/contentcapture/IContentProtectionAllowlistCallback.aidl
new file mode 100644
index 0000000..8d5a15c
--- /dev/null
+++ b/core/java/android/service/contentcapture/IContentProtectionAllowlistCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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 android.service.contentcapture;
+
+import android.content.ComponentName;
+import android.view.contentcapture.ContentCaptureCondition;
+import android.service.contentcapture.FlushMetrics;
+import android.content.ContentCaptureOptions;
+
+import java.util.List;
+
+/**
+ * Interface for the callback used by the content protection service to call the system server and
+ * update the allowlist.
+ *
+ * @hide
+ */
+oneway interface IContentProtectionAllowlistCallback {
+ void setAllowlist(in List<String> packages);
+}
diff --git a/core/java/android/service/contentcapture/IContentProtectionService.aidl b/core/java/android/service/contentcapture/IContentProtectionService.aidl
index 4a13c3f..25b248f 100644
--- a/core/java/android/service/contentcapture/IContentProtectionService.aidl
+++ b/core/java/android/service/contentcapture/IContentProtectionService.aidl
@@ -17,6 +17,7 @@
package android.service.contentcapture;
import android.content.pm.ParceledListSlice;
+import android.os.IBinder;
import android.view.contentcapture.ContentCaptureEvent;
/**
@@ -27,4 +28,6 @@
oneway interface IContentProtectionService {
void onLoginDetected(in ParceledListSlice events);
+
+ void onUpdateAllowlistRequest(in IBinder callback);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c10fc9f..6c3b8ab 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -525,11 +525,11 @@
out InputChannel inputChannel);
/**
- * Destroy an input consumer by name and display id.
+ * Destroy an input consumer by token and display id.
* This method will also dispose the input channels associated with that InputConsumer.
*/
@UnsupportedAppUsage
- boolean destroyInputConsumer(String name, int displayId);
+ boolean destroyInputConsumer(IBinder token, int displayId);
/**
* Return the touch region for the current IME window, or an empty region if there is none.
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 5f612d6b..970baf2 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -411,6 +411,15 @@
public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS =
"content_protection_allowlist_timeout_ms";
+ /**
+ * Sets the auto disconnect timeout for the content protection service in milliseconds.
+ *
+ * @hide
+ */
+ // Unit can't be in the name in order to pass the checkstyle hook, line would be too long.
+ public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT =
+ "content_protection_auto_disconnect_timeout_ms";
+
/** @hide */
@TestApi
public static final int LOGGING_LEVEL_OFF = 0;
@@ -465,6 +474,8 @@
public static final long DEFAULT_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS = 30000;
/** @hide */
public static final long DEFAULT_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS = 250;
+ /** @hide */
+ public static final long DEFAULT_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT_MS = 3000;
private final Object mLock = new Object();
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index f19a2f9..3078801 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -104,7 +104,6 @@
import com.android.internal.R;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.internal.util.ContrastColorUtil;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.IRemoteViewsFactory;
@@ -130,7 +129,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Stack;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -225,10 +223,8 @@
private static final int BITMAP_REFLECTION_ACTION_TAG = 12;
private static final int TEXT_VIEW_SIZE_ACTION_TAG = 13;
private static final int VIEW_PADDING_ACTION_TAG = 14;
- private static final int SET_REMOTE_VIEW_ADAPTER_LIST_TAG = 15;
private static final int SET_REMOTE_INPUTS_ACTION_TAG = 18;
private static final int LAYOUT_PARAM_ACTION_TAG = 19;
- private static final int OVERRIDE_TEXT_COLORS_TAG = 20;
private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21;
private static final int SET_INT_TAG_TAG = 22;
private static final int REMOVE_FROM_PARENT_ACTION_TAG = 23;
@@ -494,17 +490,6 @@
}
/**
- * Override all text colors in this layout and replace them by the given text color.
- *
- * @param textColor The color to use.
- *
- * @hide
- */
- public void overrideTextColors(int textColor) {
- addAction(new OverrideTextColorsAction(textColor));
- }
-
- /**
* Sets an integer tag to the view.
*
* @hide
@@ -640,7 +625,7 @@
*
* SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
*/
- private abstract static class Action implements Parcelable {
+ private abstract static class Action {
@IdRes
@UnsupportedAppUsage
int mViewId;
@@ -652,10 +637,6 @@
public static final int MERGE_APPEND = 1;
public static final int MERGE_IGNORE = 2;
- public int describeContents() {
- return 0;
- }
-
public void setHierarchyRootData(HierarchyRootData root) {
// Do nothing
}
@@ -689,6 +670,8 @@
public void visitUris(@NonNull Consumer<Uri> visitor) {
// Nothing to visit by default.
}
+
+ public abstract void writeToParcel(Parcel dest, int flags);
}
/**
@@ -1020,86 +1003,6 @@
}
}
- private static class SetRemoteViewsAdapterList extends Action {
- int mViewTypeCount;
- ArrayList<RemoteViews> mList;
-
- public SetRemoteViewsAdapterList(@IdRes int id, ArrayList<RemoteViews> list,
- int viewTypeCount) {
- this.mViewId = id;
- this.mList = list;
- this.mViewTypeCount = viewTypeCount;
- }
-
- public SetRemoteViewsAdapterList(Parcel parcel) {
- mViewId = parcel.readInt();
- mViewTypeCount = parcel.readInt();
- mList = parcel.createTypedArrayList(RemoteViews.CREATOR);
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mViewId);
- dest.writeInt(mViewTypeCount);
- dest.writeTypedList(mList, flags);
- }
-
- @Override
- public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
- final View target = root.findViewById(mViewId);
- if (target == null) return;
-
- // Ensure that we are applying to an AppWidget root
- if (!(rootParent instanceof AppWidgetHostView)) {
- Log.e(LOG_TAG, "SetRemoteViewsAdapterIntent action can only be used for " +
- "AppWidgets (root id: " + mViewId + ")");
- return;
- }
- // Ensure that we are calling setRemoteAdapter on an AdapterView that supports it
- if (!(target instanceof AbsListView) && !(target instanceof AdapterViewAnimator)) {
- Log.e(LOG_TAG, "Cannot setRemoteViewsAdapter on a view which is not " +
- "an AbsListView or AdapterViewAnimator (id: " + mViewId + ")");
- return;
- }
-
- if (target instanceof AbsListView) {
- AbsListView v = (AbsListView) target;
- Adapter a = v.getAdapter();
- if (a instanceof RemoteViewsListAdapter && mViewTypeCount <= a.getViewTypeCount()) {
- ((RemoteViewsListAdapter) a).setViewsList(mList);
- } else {
- v.setAdapter(new RemoteViewsListAdapter(v.getContext(), mList, mViewTypeCount,
- params.colorResources));
- }
- } else if (target instanceof AdapterViewAnimator) {
- AdapterViewAnimator v = (AdapterViewAnimator) target;
- Adapter a = v.getAdapter();
- if (a instanceof RemoteViewsListAdapter && mViewTypeCount <= a.getViewTypeCount()) {
- ((RemoteViewsListAdapter) a).setViewsList(mList);
- } else {
- v.setAdapter(new RemoteViewsListAdapter(v.getContext(), mList, mViewTypeCount,
- params.colorResources));
- }
- }
- }
-
- @Override
- public int getActionTag() {
- return SET_REMOTE_VIEW_ADAPTER_LIST_TAG;
- }
-
- @Override
- public String getUniqueKey() {
- return (SET_REMOTE_ADAPTER_TAG + "_" + mViewId);
- }
-
- @Override
- public void visitUris(@NonNull Consumer<Uri> visitor) {
- for (RemoteViews remoteViews : mList) {
- remoteViews.visitUris(visitor);
- }
- }
- }
-
/**
* Cache of {@link ApplicationInfo}s that can be used to ensure that the same
* {@link ApplicationInfo} instance is used throughout the RemoteViews.
@@ -3491,51 +3394,6 @@
}
}
- /**
- * Helper action to override all textViewColors
- */
- private static class OverrideTextColorsAction extends Action {
- private final int mTextColor;
-
- public OverrideTextColorsAction(int textColor) {
- this.mTextColor = textColor;
- }
-
- public OverrideTextColorsAction(Parcel parcel) {
- mTextColor = parcel.readInt();
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mTextColor);
- }
-
- @Override
- public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
- // Let's traverse the viewtree and override all textColors!
- Stack<View> viewsToProcess = new Stack<>();
- viewsToProcess.add(root);
- while (!viewsToProcess.isEmpty()) {
- View v = viewsToProcess.pop();
- if (v instanceof TextView) {
- TextView textView = (TextView) v;
- textView.setText(ContrastColorUtil.clearColorSpans(textView.getText()));
- textView.setTextColor(mTextColor);
- }
- if (v instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) v;
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- viewsToProcess.push(viewGroup.getChildAt(i));
- }
- }
- }
- }
-
- @Override
- public int getActionTag() {
- return OVERRIDE_TEXT_COLORS_TAG;
- }
- }
-
private static class SetIntTagAction extends Action {
@IdRes private final int mViewId;
@IdRes private final int mKey;
@@ -4156,14 +4014,10 @@
return new ViewPaddingAction(parcel);
case BITMAP_REFLECTION_ACTION_TAG:
return new BitmapReflectionAction(parcel);
- case SET_REMOTE_VIEW_ADAPTER_LIST_TAG:
- return new SetRemoteViewsAdapterList(parcel);
case SET_REMOTE_INPUTS_ACTION_TAG:
return new SetRemoteInputsAction(parcel);
case LAYOUT_PARAM_ACTION_TAG:
return new LayoutParamAction(parcel);
- case OVERRIDE_TEXT_COLORS_TAG:
- return new OverrideTextColorsAction(parcel);
case SET_RIPPLE_DRAWABLE_COLOR_TAG:
return new SetRippleDrawableColor(parcel);
case SET_INT_TAG_TAG:
@@ -4910,7 +4764,11 @@
@Deprecated
public void setRemoteAdapter(@IdRes int viewId, ArrayList<RemoteViews> list,
int viewTypeCount) {
- addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
+ RemoteCollectionItems.Builder b = new RemoteCollectionItems.Builder();
+ for (int i = 0; i < list.size(); i++) {
+ b.addItem(i, list.get(i));
+ }
+ setRemoteAdapter(viewId, b.setViewTypeCount(viewTypeCount).build());
}
/**
diff --git a/core/java/android/widget/RemoteViewsListAdapter.java b/core/java/android/widget/RemoteViewsListAdapter.java
deleted file mode 100644
index 46f80f3..0000000
--- a/core/java/android/widget/RemoteViewsListAdapter.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2012 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.widget;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-
-/**
- * @hide
- */
-public class RemoteViewsListAdapter extends BaseAdapter {
-
- private Context mContext;
- private ArrayList<RemoteViews> mRemoteViewsList;
- private ArrayList<Integer> mViewTypes = new ArrayList<Integer>();
- private int mViewTypeCount;
- private RemoteViews.ColorResources mColorResources;
-
- public RemoteViewsListAdapter(Context context, ArrayList<RemoteViews> remoteViews,
- int viewTypeCount, RemoteViews.ColorResources colorResources) {
- mContext = context;
- mRemoteViewsList = remoteViews;
- mViewTypeCount = viewTypeCount;
- mColorResources = colorResources;
- init();
- }
-
- public void setViewsList(ArrayList<RemoteViews> remoteViews) {
- mRemoteViewsList = remoteViews;
- init();
- notifyDataSetChanged();
- }
-
- private void init() {
- if (mRemoteViewsList == null) return;
-
- mViewTypes.clear();
- for (RemoteViews rv: mRemoteViewsList) {
- if (!mViewTypes.contains(rv.getLayoutId())) {
- mViewTypes.add(rv.getLayoutId());
- }
- }
-
- if (mViewTypes.size() > mViewTypeCount || mViewTypeCount < 1) {
- throw new RuntimeException("Invalid view type count -- view type count must be >= 1" +
- "and must be as large as the total number of distinct view types");
- }
- }
-
- @Override
- public int getCount() {
- if (mRemoteViewsList != null) {
- return mRemoteViewsList.size();
- } else {
- return 0;
- }
- }
-
- @Override
- public Object getItem(int position) {
- return null;
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (position < getCount()) {
- RemoteViews rv = mRemoteViewsList.get(position);
- rv.addFlags(RemoteViews.FLAG_WIDGET_IS_COLLECTION_CHILD);
- View v;
- if (convertView != null && convertView.getId() == rv.getLayoutId()) {
- v = convertView;
- rv.reapply(mContext, v, null /* handler */, null /* size */, mColorResources);
- } else {
- v = rv.apply(mContext, parent, null /* handler */, null /* size */,
- mColorResources);
- }
- return v;
- } else {
- return null;
- }
- }
-
- @Override
- public int getItemViewType(int position) {
- if (position < getCount()) {
- int layoutId = mRemoteViewsList.get(position).getLayoutId();
- return mViewTypes.indexOf(layoutId);
- } else {
- return 0;
- }
- }
-
- public int getViewTypeCount() {
- return mViewTypeCount;
- }
-
- @Override
- public boolean hasStableIds() {
- return false;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index cb5d1c4..03c546d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -386,7 +386,8 @@
// two gestures are waiting to be processed at the moment, skip any further user touches
if (mCurrentTracker.isFinished() && mQueuedTracker.isFinished()) {
- Log.d(TAG, "Ignoring MotionEvent because two gestures are already being queued.");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+ "Ignoring MotionEvent because two gestures are already being queued.");
return;
}
@@ -420,7 +421,8 @@
} else if (mQueuedTracker.isInInitialState()) {
touchTracker = mQueuedTracker;
} else {
- Log.w(TAG, "Cannot start tracking new gesture with neither tracker in initial state.");
+ ProtoLog.w(WM_SHELL_BACK_PREVIEW,
+ "Cannot start tracking new gesture with neither tracker in initial state.");
return;
}
touchTracker.setGestureStartLocation(touchX, touchY, swipeEdge);
@@ -449,7 +451,7 @@
@NonNull TouchTracker touchTracker) {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Received backNavigationInfo:%s", backNavigationInfo);
if (backNavigationInfo == null) {
- Log.e(TAG, "Received BackNavigationInfo is null.");
+ ProtoLog.e(WM_SHELL_BACK_PREVIEW, "Received BackNavigationInfo is null.");
return;
}
final int backType = backNavigationInfo.getType();
@@ -475,7 +477,7 @@
}
private void injectBackKey() {
- Log.d(TAG, "injectBackKey");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "injectBackKey");
sendBackEvent(KeyEvent.ACTION_DOWN);
sendBackEvent(KeyEvent.ACTION_UP);
}
@@ -491,7 +493,7 @@
ev.setDisplayId(mContext.getDisplay().getDisplayId());
if (!mContext.getSystemService(InputManager.class)
.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) {
- Log.e(TAG, "Inject input event fail");
+ ProtoLog.e(WM_SHELL_BACK_PREVIEW, "Inject input event fail");
}
}
@@ -669,7 +671,8 @@
TouchTracker activeTouchTracker = getActiveTracker();
if (!mBackGestureStarted || activeTouchTracker == null) {
// This can happen when an unfinished gesture has been reset in resetTouchTracker
- Log.d(TAG, "onGestureFinished called while no gesture is started");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+ "onGestureFinished called while no gesture is started");
return;
}
boolean triggerBack = activeTouchTracker.getTriggerBack();
@@ -687,8 +690,8 @@
// No focus window found or core are running recents animation, inject back key as
// legacy behavior, or new back gesture was started while previous has not finished yet
if (!mQueuedTracker.isInInitialState()) {
- Log.e(TAG, "mBackNavigationInfo is null AND there is another back animation in "
- + "progress");
+ ProtoLog.e(WM_SHELL_BACK_PREVIEW, "mBackNavigationInfo is null AND there is "
+ + "another back animation in progress");
}
mCurrentTracker.reset();
if (triggerBack) {
@@ -702,7 +705,7 @@
// Simply trigger and finish back navigation when no animator defined.
if (!shouldDispatchToAnimator()
|| mShellBackAnimationRegistry.isAnimationCancelledOrNull(backType)) {
- Log.d(TAG, "Trigger back without dispatching to animator.");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Trigger back without dispatching to animator.");
invokeOrCancelBack(mCurrentTracker);
mCurrentTracker.reset();
return;
@@ -748,13 +751,14 @@
mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable);
mPostCommitAnimationInProgress = false;
- Log.d(TAG, "BackAnimationController: onBackAnimationFinished()");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: onBackAnimationFinished()");
if (mCurrentTracker.isActive() || mCurrentTracker.isFinished()) {
// Trigger the real back.
invokeOrCancelBack(mCurrentTracker);
} else {
- Log.d(TAG, "mCurrentBackGestureInfo was null when back animation finished");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+ "mCurrentBackGestureInfo was null when back animation finished");
}
resetTouchTracker();
}
@@ -773,23 +777,25 @@
mBackGestureStarted = false;
dispatchOnBackCancelled(mActiveCallback);
finishBackNavigation(false);
- Log.d(TAG, "resetTouchTracker -> reset an unfinished gesture");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+ "resetTouchTracker -> reset an unfinished gesture");
} else {
- Log.d(TAG, "resetTouchTracker -> no queued gesture");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "resetTouchTracker -> no queued gesture");
}
return;
}
if (mCurrentTracker.isFinished() && mCurrentTracker.getTriggerBack()) {
- Log.d(TAG, "resetTouchTracker -> start queued back navigation AND post commit "
- + "animation");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "resetTouchTracker -> start queued back navigation "
+ + "AND post commit animation");
injectBackKey();
finishBackNavigation(true);
mCurrentTracker.reset();
} else if (!mCurrentTracker.isFinished()) {
- Log.d(TAG, "resetTouchTracker -> queued gesture not finished; do nothing");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+ "resetTouchTracker -> queued gesture not finished; do nothing");
} else {
- Log.d(TAG, "resetTouchTracker -> reset queued gesture");
+ ProtoLog.d(WM_SHELL_BACK_PREVIEW, "resetTouchTracker -> reset queued gesture");
mCurrentTracker.reset();
}
}
@@ -821,7 +827,8 @@
mShellExecutor.execute(
() -> {
if (mBackNavigationInfo == null) {
- Log.e(TAG, "Lack of navigation info to start animation.");
+ ProtoLog.e(WM_SHELL_BACK_PREVIEW,
+ "Lack of navigation info to start animation.");
return;
}
final BackAnimationRunner runner =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
index 8e3376f..f6cab48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -139,7 +139,7 @@
final InputChannel inputChannel = new InputChannel();
try {
// TODO(b/113087003): Support Picture-in-picture in multi-display.
- mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+ mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY);
mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
} catch (RemoteException e) {
ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
@@ -163,7 +163,7 @@
}
try {
// TODO(b/113087003): Support Picture-in-picture in multi-display.
- mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+ mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY);
} catch (RemoteException e) {
ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Failed to destroy input consumer, %s", TAG, e);
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index ce0772f..f074106 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -607,6 +607,8 @@
userType = UserIconInfo.TYPE_CLONED;
} else if (ui.isManagedProfile()) {
userType = UserIconInfo.TYPE_WORK;
+ } else if (ui.isPrivateProfile()) {
+ userType = UserIconInfo.TYPE_PRIVATE;
}
}
} catch (Exception e) {
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 572f6ff..1a37e2d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -977,4 +977,13 @@
Width in pixels of the Side FPS sensor.
-->
<integer name="config_sfpsSensorWidth">200</integer>
+
+ <!--
+ They are service names that, if enabled, will cause the magnification settings button
+ to never hide after timeout.
+ -->
+ <string-array name="services_always_show_magnification_settings" translatable="false">
+ <item>com.android.switchaccess.SwitchAccessService</item>
+ <item>com.google.android.apps.accessibility.voiceaccess.JustSpeakService</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index ba0a6d1..b406e72 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -139,7 +139,7 @@
if (mInputEventReceiver == null) {
final InputChannel inputChannel = new InputChannel();
try {
- mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+ mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY);
mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
} catch (RemoteException e) {
Log.e(TAG, "Failed to create input consumer", e);
@@ -158,7 +158,7 @@
public void unregisterInputConsumer() {
if (mInputEventReceiver != null) {
try {
- mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+ mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY);
} catch (RemoteException e) {
Log.e(TAG, "Failed to destroy input consumer", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 84f1395..d9d9e37 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -20,12 +20,14 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
import android.annotation.UiContext;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -49,6 +51,8 @@
import com.android.systemui.res.R;
import java.util.Collections;
+import java.util.Optional;
+import java.util.Set;
/**
* Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of
@@ -315,10 +319,46 @@
DEFAULT_FADE_OUT_ANIMATION_DELAY_MS,
AccessibilityManager.FLAG_CONTENT_ICONS
| AccessibilityManager.FLAG_CONTENT_CONTROLS);
+ if (shouldAlwaysShowSettings()) {
+ mUiTimeout = -1;
+ }
}
// Refresh the time slot of the fade-out task whenever this method is called.
stopFadeOutAnimation();
- mImageView.postOnAnimationDelayed(mFadeOutAnimationTask, mUiTimeout);
+ if (mUiTimeout >= 0) {
+ mImageView.postOnAnimationDelayed(mFadeOutAnimationTask, mUiTimeout);
+ }
+ }
+
+ private boolean shouldAlwaysShowSettings() {
+ try {
+ var serviceNamesArray = mContext.getResources().getStringArray(
+ R.array.services_always_show_magnification_settings);
+ if (serviceNamesArray.length == 0) {
+ return false;
+ }
+ Set serviceNamesSet = Set.of(serviceNamesArray);
+
+ var serviceInfoList = mAccessibilityManager
+ .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ for (var serviceInfo : serviceInfoList) {
+ var serviceName = Optional.ofNullable(serviceInfo)
+ .map(AccessibilityServiceInfo::getResolveInfo)
+ .map(resolveInfo -> resolveInfo.serviceInfo)
+ .map(resolvedServiceInfo -> resolvedServiceInfo.name)
+ .orElse(null);
+ if (serviceName == null) {
+ continue;
+ }
+
+ if (serviceNamesSet.contains(serviceName)) {
+ return true;
+ }
+ }
+ } catch (Resources.NotFoundException nfe) {
+ // No-op. Do not crash for not finding resources.
+ }
+ return false;
}
private void stopFadeOutAnimation() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
index 62c5988..755549b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
@@ -60,8 +60,7 @@
private val deviceEntryIconViewId = R.id.device_entry_icon_view
override fun addViews(constraintLayout: ConstraintLayout) {
- if (
- !featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON) &&
+ if (!featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON) &&
!featureFlags.isEnabled(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS)
) {
return
@@ -76,7 +75,7 @@
DeviceEntryIconView(context, null).apply { id = deviceEntryIconViewId }
} else {
// Flags.MIGRATE_LOCK_ICON
- LockIconView(context, null).apply { id = deviceEntryIconViewId }
+ LockIconView(context, null).apply { id = R.id.lock_icon_view }
}
constraintLayout.addView(view)
}
@@ -91,7 +90,7 @@
)
}
} else {
- constraintLayout.findViewById<LockIconView?>(deviceEntryIconViewId)?.let {
+ constraintLayout.findViewById<LockIconView?>(R.id.lock_icon_view)?.let {
lockIconViewController.get().setLockIconView(it)
}
}
@@ -133,7 +132,11 @@
}
override fun removeViews(constraintLayout: ConstraintLayout) {
- constraintLayout.removeView(deviceEntryIconViewId)
+ if (featureFlags.isEnabled(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS)) {
+ constraintLayout.removeView(deviceEntryIconViewId)
+ } else {
+ constraintLayout.removeView(R.id.lock_icon_view)
+ }
}
@VisibleForTesting
@@ -148,18 +151,25 @@
)
}
+ val iconId =
+ if (featureFlags.isEnabled(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS)) {
+ deviceEntryIconViewId
+ } else {
+ R.id.lock_icon_view
+ }
+
constraintSet.apply {
- constrainWidth(deviceEntryIconViewId, sensorRect.right - sensorRect.left)
- constrainHeight(deviceEntryIconViewId, sensorRect.bottom - sensorRect.top)
+ constrainWidth(iconId, sensorRect.right - sensorRect.left)
+ constrainHeight(iconId, sensorRect.bottom - sensorRect.top)
connect(
- deviceEntryIconViewId,
+ iconId,
ConstraintSet.TOP,
ConstraintSet.PARENT_ID,
ConstraintSet.TOP,
sensorRect.top
)
connect(
- deviceEntryIconViewId,
+ iconId,
ConstraintSet.START,
ConstraintSet.PARENT_ID,
ConstraintSet.START,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 8fd2bd6a..1a88545 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -49,8 +49,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Handler;
@@ -71,8 +74,8 @@
import androidx.test.filters.SmallTest;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.After;
import org.junit.Before;
@@ -186,6 +189,87 @@
}
@Test
+ public void showMagnificationButton_noA11yServicesRunning_postDelayedAnimationsWithTimeout() {
+ final int a11yTimeout = 12345;
+ when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn(
+ a11yTimeout);
+ when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+ .thenReturn(List.of());
+
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+ verify(mAccessibilityManager).getRecommendedTimeoutMillis(
+ DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS
+ | AccessibilityManager.FLAG_CONTENT_CONTROLS);
+ verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout));
+ }
+
+ @Test
+ public void showMagnificationButton_voiceAccessRunning_noTimeout() {
+ var serviceInfo = createServiceInfoWithName(
+ "com.google.android.apps.accessibility.voiceaccess.JustSpeakService");
+ when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+ .thenReturn(List.of(serviceInfo));
+
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+ verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong());
+ }
+
+ @Test
+ public void showMagnificationButton_switchAccessRunning_noTimeout() {
+ var serviceInfo = createServiceInfoWithName(
+ "com.android.switchaccess.SwitchAccessService");
+ when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+ .thenReturn(List.of(serviceInfo));
+
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+ verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong());
+ }
+
+ @Test
+ public void showMagnificationButton_switchAccessAndVoiceAccessBothRunning_noTimeout() {
+ var switchAccessServiceInfo = createServiceInfoWithName(
+ "com.android.switchaccess.SwitchAccessService");
+ var voiceAccessServiceInfo = createServiceInfoWithName(
+ "com.google.android.apps.accessibility.voiceaccess.JustSpeakService");
+ when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+ .thenReturn(List.of(switchAccessServiceInfo, voiceAccessServiceInfo));
+
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+ verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong());
+ }
+
+ @Test
+ public void showMagnificationButton_someOtherServiceRunning_postDelayedAnimationsWithTimeout() {
+ final int a11yTimeout = 12345;
+ when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn(
+ a11yTimeout);
+ var serviceInfo1 = createServiceInfoWithName("com.test.someService1");
+ var serviceInfo2 = createServiceInfoWithName("com.test.someService2");
+ when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+ .thenReturn(List.of(serviceInfo1, serviceInfo2));
+
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+ verify(mAccessibilityManager).getRecommendedTimeoutMillis(
+ DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS
+ | AccessibilityManager.FLAG_CONTENT_CONTROLS);
+ verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout));
+ }
+
+ private AccessibilityServiceInfo createServiceInfoWithName(String name) {
+ var resolveInfo = new ResolveInfo();
+ resolveInfo.serviceInfo = new ServiceInfo();
+ resolveInfo.serviceInfo.name = name;
+ var serviceInfo = new AccessibilityServiceInfo();
+ serviceInfo.setResolveInfo(resolveInfo);
+ return serviceInfo;
+ }
+
+ @Test
public void showMagnificationButton_windowModeAndFadingOut_verifyAnimationEndAction() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
executeFadeOutAnimation();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
index 5f22c7d..c7f7c3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
@@ -106,7 +106,20 @@
}
@Test
- fun applyConstraints() {
+ fun applyConstraints_udfps_refactor_off() {
+ featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, false)
+ val cs = ConstraintSet()
+ underTest.applyConstraints(cs)
+
+ val constraint = cs.getConstraint(R.id.lock_icon_view)
+
+ assertThat(constraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID)
+ assertThat(constraint.layout.startToStart).isEqualTo(ConstraintSet.PARENT_ID)
+ }
+
+ @Test
+ fun applyConstraints_udfps_refactor_on() {
+ featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
val cs = ConstraintSet()
underTest.applyConstraints(cs)
@@ -117,7 +130,24 @@
}
@Test
- fun testCenterIcon() {
+ fun testCenterIcon_udfps_refactor_off() {
+ featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, false)
+ val cs = ConstraintSet()
+ underTest.centerIcon(Point(5, 6), 1F, cs)
+
+ val constraint = cs.getConstraint(R.id.lock_icon_view)
+
+ assertThat(constraint.layout.mWidth).isEqualTo(2)
+ assertThat(constraint.layout.mHeight).isEqualTo(2)
+ assertThat(constraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID)
+ assertThat(constraint.layout.startToStart).isEqualTo(ConstraintSet.PARENT_ID)
+ assertThat(constraint.layout.topMargin).isEqualTo(5)
+ assertThat(constraint.layout.startMargin).isEqualTo(4)
+ }
+
+ @Test
+ fun testCenterIcon_udfps_refactor_on() {
+ featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
val cs = ConstraintSet()
underTest.centerIcon(Point(5, 6), 1F, cs)
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 9f4528b..b2ff3c3 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -22,9 +22,12 @@
import static android.view.contentcapture.ContentCaptureHelper.toList;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
@@ -227,6 +230,9 @@
@GuardedBy("mLock")
long mDevCfgContentProtectionAllowlistTimeoutMs;
+ @GuardedBy("mLock")
+ long mDevCfgContentProtectionAutoDisconnectTimeoutMs;
+
private final Executor mDataShareExecutor = Executors.newCachedThreadPool();
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -435,14 +441,15 @@
case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
case ContentCaptureManager
.DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING:
- case ContentCaptureManager
- .DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER:
- case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE:
+ // Content protection below
+ case DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER:
+ case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE:
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG:
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG:
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD:
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS:
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS:
+ case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT:
setFineTuneParamsFromDeviceConfig();
return;
default:
@@ -502,8 +509,7 @@
mDevCfgContentProtectionBufferSize =
DeviceConfig.getInt(
DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
- ContentCaptureManager
- .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE,
+ DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE,
ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE);
contentProtectionRequiredGroupsConfig =
DeviceConfig.getString(
@@ -533,7 +539,12 @@
DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS,
ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS);
-
+ mDevCfgContentProtectionAutoDisconnectTimeoutMs =
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT,
+ ContentCaptureManager
+ .DEFAULT_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT_MS);
contentProtectionAllowlistManagerOld = mContentProtectionAllowlistManager;
if (verbose) {
@@ -565,7 +576,9 @@
+ ", contentProtectionAllowlistDelayMs="
+ contentProtectionAllowlistDelayMs
+ ", contentProtectionAllowlistTimeoutMs="
- + contentProtectionAllowlistTimeoutMs);
+ + contentProtectionAllowlistTimeoutMs
+ + ", contentProtectionAutoDisconnectTimeoutMs="
+ + mDevCfgContentProtectionAutoDisconnectTimeoutMs);
}
}
@@ -893,6 +906,9 @@
pw.print(prefix2);
pw.print("contentProtectionAllowlistTimeoutMs: ");
pw.println(mDevCfgContentProtectionAllowlistTimeoutMs);
+ pw.print(prefix2);
+ pw.print("contentProtectionAutoDisconnectTimeoutMs: ");
+ pw.println(mDevCfgContentProtectionAutoDisconnectTimeoutMs);
pw.print(prefix);
pw.println("Global Options:");
mGlobalContentCaptureOptions.dump(prefix2, pw);
@@ -962,12 +978,14 @@
@Nullable
public RemoteContentProtectionService createRemoteContentProtectionService() {
ComponentName componentName;
+ long autoDisconnectTimeoutMs;
synchronized (mLock) {
if (!mDevCfgEnableContentProtectionReceiver
|| mContentProtectionServiceComponentName == null) {
return null;
}
componentName = mContentProtectionServiceComponentName;
+ autoDisconnectTimeoutMs = mDevCfgContentProtectionAutoDisconnectTimeoutMs;
}
// Check permissions by trying to construct {@link ContentCaptureServiceInfo}
@@ -978,19 +996,20 @@
return null;
}
- return createRemoteContentProtectionService(componentName);
+ return createRemoteContentProtectionService(componentName, autoDisconnectTimeoutMs);
}
/** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@NonNull
protected RemoteContentProtectionService createRemoteContentProtectionService(
- @NonNull ComponentName componentName) {
+ @NonNull ComponentName componentName, long autoDisconnectTimeoutMs) {
return new RemoteContentProtectionService(
getContext(),
componentName,
UserHandle.getCallingUserId(),
- isBindInstantServiceAllowed());
+ isBindInstantServiceAllowed(),
+ autoDisconnectTimeoutMs);
}
/** @hide */
diff --git a/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java b/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java
index dd5545d..bc11fc3 100644
--- a/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java
+++ b/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java
@@ -22,14 +22,13 @@
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.IContentProtectionAllowlistCallback;
import android.service.contentcapture.IContentProtectionService;
import android.util.Slog;
import android.view.contentcapture.ContentCaptureEvent;
import com.android.internal.infra.ServiceConnector;
-import java.time.Duration;
-
/**
* Connector for the remote content protection service.
*
@@ -40,15 +39,16 @@
private static final String TAG = RemoteContentProtectionService.class.getSimpleName();
- private static final Duration AUTO_DISCONNECT_TIMEOUT = Duration.ofSeconds(3);
-
@NonNull private final ComponentName mComponentName;
+ private final long mAutoDisconnectTimeoutMs;
+
public RemoteContentProtectionService(
@NonNull Context context,
@NonNull ComponentName componentName,
int userId,
- boolean bindAllowInstant) {
+ boolean bindAllowInstant,
+ long autoDisconnectTimeoutMs) {
super(
context,
new Intent(ContentCaptureService.PROTECTION_SERVICE_INTERFACE)
@@ -57,11 +57,12 @@
userId,
IContentProtectionService.Stub::asInterface);
mComponentName = componentName;
+ mAutoDisconnectTimeoutMs = autoDisconnectTimeoutMs;
}
@Override // from ServiceConnector.Impl
protected long getAutoDisconnectTimeoutMs() {
- return AUTO_DISCONNECT_TIMEOUT.toMillis();
+ return mAutoDisconnectTimeoutMs;
}
@Override // from ServiceConnector.Impl
@@ -75,7 +76,13 @@
+ (isConnected ? "connected" : "disconnected"));
}
+ /** Calls the remote service when login is detected. */
public void onLoginDetected(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
run(service -> service.onLoginDetected(events));
}
+
+ /** Calls the remote service with a request to update allowlist. */
+ public void onUpdateAllowlistRequest(@NonNull IContentProtectionAllowlistCallback callback) {
+ run(service -> service.onUpdateAllowlistRequest(callback.asBinder()));
+ }
}
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index cb4cf9d..4579cc1 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -422,8 +422,9 @@
}
BalVerdict resultForCaller = checkBackgroundActivityStartAllowedByCaller(state);
- BalVerdict resultForRealCaller = callingUid == realCallingUid
+ BalVerdict resultForRealCaller = callingUid == realCallingUid && resultForCaller.allows()
? resultForCaller // no need to calculate again
+ // otherwise we might need to recalculate because the logic is not the same
: checkBackgroundActivityStartAllowedBySender(state, checkedOptions);
if (resultForCaller.allows()
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 1fa7d2a..34d7651 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -160,7 +160,7 @@
if (dc == null) {
return;
}
- dc.getInputMonitor().destroyInputConsumer(mName);
+ dc.getInputMonitor().destroyInputConsumer(mToken);
unlinkFromDeathRecipient();
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 5c0bc28..61fea4d 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -73,6 +73,7 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.Set;
import java.util.function.Consumer;
@@ -104,7 +105,7 @@
* The set of input consumer added to the window manager by name, which consumes input events
* for the windows below it.
*/
- private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
+ private final ArrayList<InputConsumerImpl> mInputConsumers = new ArrayList<>();
/**
* Set when recents (overview) is active as part of a shell transition. While set, any focus
@@ -164,31 +165,35 @@
mDisplayRemoved = true;
}
- private void addInputConsumer(String name, InputConsumerImpl consumer) {
- mInputConsumers.put(name, consumer);
+ private void addInputConsumer(InputConsumerImpl consumer) {
+ mInputConsumers.add(consumer);
consumer.linkToDeathRecipient();
consumer.layout(mInputTransaction, mDisplayWidth, mDisplayHeight);
updateInputWindowsLw(true /* force */);
}
- boolean destroyInputConsumer(String name) {
- if (disposeInputConsumer(mInputConsumers.remove(name))) {
- updateInputWindowsLw(true /* force */);
- return true;
- }
- return false;
- }
-
- private boolean disposeInputConsumer(InputConsumerImpl consumer) {
- if (consumer != null) {
- consumer.disposeChannelsLw(mInputTransaction);
- return true;
+ boolean destroyInputConsumer(IBinder token) {
+ for (int i = 0; i < mInputConsumers.size(); i++) {
+ final InputConsumerImpl consumer = mInputConsumers.get(i);
+ if (consumer != null && consumer.mToken == token) {
+ consumer.disposeChannelsLw(mInputTransaction);
+ mInputConsumers.remove(consumer);
+ updateInputWindowsLw(true /* force */);
+ return true;
+ }
}
return false;
}
InputConsumerImpl getInputConsumer(String name) {
- return mInputConsumers.get(name);
+ // Search in reverse order as the latest input consumer with the name takes precedence
+ for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
+ final InputConsumerImpl consumer = mInputConsumers.get(i);
+ if (consumer.mName.equals(name)) {
+ return consumer;
+ }
+ }
+ return null;
}
void layoutInputConsumers(int dw, int dh) {
@@ -200,7 +205,7 @@
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "layoutInputConsumer");
for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
- mInputConsumers.valueAt(i).layout(mInputTransaction, dw, dh);
+ mInputConsumers.get(i).layout(mInputTransaction, dw, dh);
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -212,15 +217,16 @@
// (set so by this function) and must meet some condition for visibility on each update.
void resetInputConsumers(SurfaceControl.Transaction t) {
for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
- mInputConsumers.valueAt(i).hide(t);
+ mInputConsumers.get(i).hide(t);
}
}
void createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid,
UserHandle clientUser) {
- if (mInputConsumers.containsKey(name)) {
+ final InputConsumerImpl existingConsumer = getInputConsumer(name);
+ if (existingConsumer != null && existingConsumer.mClientUser.equals(clientUser)) {
throw new IllegalStateException("Existing input consumer found with name: " + name
- + ", display: " + mDisplayId);
+ + ", display: " + mDisplayId + ", user: " + clientUser);
}
final InputConsumerImpl consumer = new InputConsumerImpl(mService, token, name,
@@ -239,7 +245,7 @@
throw new IllegalArgumentException("Illegal input consumer : " + name
+ ", display: " + mDisplayId);
}
- addInputConsumer(name, consumer);
+ addInputConsumer(consumer);
}
@VisibleForTesting
@@ -541,11 +547,11 @@
}
void dump(PrintWriter pw, String prefix) {
- final Set<String> inputConsumerKeys = mInputConsumers.keySet();
- if (!inputConsumerKeys.isEmpty()) {
+ if (!mInputConsumers.isEmpty()) {
pw.println(prefix + "InputConsumers:");
- for (String key : inputConsumerKeys) {
- mInputConsumers.get(key).dump(pw, key, prefix);
+ for (int i = 0; i < mInputConsumers.size(); i++) {
+ final InputConsumerImpl consumer = mInputConsumers.get(i);
+ consumer.dump(pw, consumer.mName, prefix);
}
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 82d4b90..ef25726 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -1021,7 +1021,11 @@
synchronized (mService.getWindowManagerLock()) {
// Clear associated input consumers on runner death
final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
- inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
+ final InputConsumerImpl consumer = inputMonitor.getInputConsumer(
+ INPUT_CONSUMER_RECENTS_ANIMATION);
+ if (consumer != null) {
+ inputMonitor.destroyInputConsumer(consumer.mToken);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a90e08e..9fb7e8d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6553,7 +6553,7 @@
}
@Override
- public boolean destroyInputConsumer(String name, int displayId) {
+ public boolean destroyInputConsumer(IBinder token, int displayId) {
if (!mAtmService.isCallerRecents(Binder.getCallingUid())
&& mContext.checkCallingOrSelfPermission(INPUT_CONSUMER) != PERMISSION_GRANTED) {
throw new SecurityException("destroyInputConsumer requires INPUT_CONSUMER permission");
@@ -6562,7 +6562,7 @@
synchronized (mGlobalLock) {
DisplayContent display = mRoot.getDisplayContent(displayId);
if (display != null) {
- return display.getInputMonitor().destroyInputConsumer(name);
+ return display.getInputMonitor().destroyInputConsumer(token);
}
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
index 9a5241e..6d13d87 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
@@ -662,7 +662,7 @@
@Override
protected RemoteContentProtectionService createRemoteContentProtectionService(
- @NonNull ComponentName componentName) {
+ @NonNull ComponentName componentName, long autoDisconnectTimeoutMs) {
mRemoteContentProtectionServicesCreated++;
return mMockRemoteContentProtectionService;
}
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java
index 9135ef3..6a7e286 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java
@@ -21,12 +21,16 @@
import static org.junit.Assert.fail;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.UserHandle;
+import android.service.contentcapture.IContentProtectionAllowlistCallback;
import android.service.contentcapture.IContentProtectionService;
import android.view.contentcapture.ContentCaptureEvent;
@@ -57,21 +61,27 @@
@SmallTest
public class RemoteContentProtectionServiceTest {
- private final Context mContext = ApplicationProvider.getApplicationContext();
+ private static final long AUTO_DISCONNECT_TIMEOUT_MS = 12345L;
+
+ private static final IBinder BINDER = new Binder();
+
+ private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock private IContentProtectionService mMockContentProtectionService;
+ @Mock private IContentProtectionAllowlistCallback mMockContentProtectionAllowlistCallback;
+
private RemoteContentProtectionService mRemoteContentProtectionService;
private int mConnectCallCount = 0;
@Before
public void setup() {
- ComponentName componentName = new ComponentName(mContext.getPackageName(), "TestClass");
+ ComponentName componentName = new ComponentName(CONTEXT.getPackageName(), "TestClass");
mRemoteContentProtectionService =
- new TestRemoteContentProtectionService(mContext, componentName);
+ new TestRemoteContentProtectionService(CONTEXT, componentName);
}
@Test
@@ -84,7 +94,7 @@
public void getAutoDisconnectTimeoutMs() {
long actual = mRemoteContentProtectionService.getAutoDisconnectTimeoutMs();
- assertThat(actual).isEqualTo(3000L);
+ assertThat(actual).isEqualTo(AUTO_DISCONNECT_TIMEOUT_MS);
}
@Test
@@ -99,10 +109,43 @@
verify(mMockContentProtectionService).onLoginDetected(events);
}
+ @Test
+ public void onUpdateAllowlistRequest() throws Exception {
+ when(mMockContentProtectionAllowlistCallback.asBinder()).thenReturn(BINDER);
+
+ mRemoteContentProtectionService.onUpdateAllowlistRequest(
+ mMockContentProtectionAllowlistCallback);
+
+ verify(mMockContentProtectionService).onUpdateAllowlistRequest(BINDER);
+ }
+
+ @Test
+ public void onServiceConnectionStatusChanged_connected_noSideEffects() {
+ mRemoteContentProtectionService.onServiceConnectionStatusChanged(
+ mMockContentProtectionService, /* isConnected= */ true);
+
+ verifyZeroInteractions(mMockContentProtectionService);
+ assertThat(mConnectCallCount).isEqualTo(0);
+ }
+
+ @Test
+ public void onServiceConnectionStatusChanged_disconnected_noSideEffects() {
+ mRemoteContentProtectionService.onServiceConnectionStatusChanged(
+ mMockContentProtectionService, /* isConnected= */ false);
+
+ verifyZeroInteractions(mMockContentProtectionService);
+ assertThat(mConnectCallCount).isEqualTo(0);
+ }
+
private final class TestRemoteContentProtectionService extends RemoteContentProtectionService {
TestRemoteContentProtectionService(Context context, ComponentName componentName) {
- super(context, componentName, UserHandle.myUserId(), /* bindAllowInstant= */ false);
+ super(
+ context,
+ componentName,
+ UserHandle.myUserId(),
+ /* bindAllowInstant= */ false,
+ AUTO_DISCONNECT_TIMEOUT_MS);
}
@Override // from ServiceConnector