summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ApiDocs.bp12
-rw-r--r--core/java/android/net/NetworkIdentity.java6
-rw-r--r--core/java/android/view/translation/UiTranslationController.java10
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java8
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java79
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java8
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java51
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationScaleProvider.java139
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java70
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java320
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java330
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputHardwareManager.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java39
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java37
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationScaleProviderTest.java100
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java8
19 files changed, 790 insertions, 480 deletions
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 1e5ae7bb6270..82759f767c3e 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -112,7 +112,6 @@ stubs_defaults {
}
// Defaults module for doc-stubs targets that use module source code as input.
-// This is the default/normal.
stubs_defaults {
name: "framework-doc-stubs-sources-default",
defaults: ["framework-doc-stubs-default"],
@@ -148,12 +147,6 @@ droidstubs {
}
droidstubs {
- name: "framework-doc-stubs",
- defaults: ["framework-doc-stubs-sources-default"],
- args: metalava_framework_docs_args,
-}
-
-droidstubs {
name: "framework-doc-system-stubs",
defaults: ["framework-doc-stubs-sources-default"],
args: metalava_framework_docs_args +
@@ -161,11 +154,8 @@ droidstubs {
api_levels_sdk_type: "system",
}
-// Experimental target building doc stubs with module stub source code as input.
-// This is intended to eventually replace framework-doc-stubs, once all diffs
-// have been eliminated.
droidstubs {
- name: "framework-doc-stubs-module-stubs",
+ name: "framework-doc-stubs",
defaults: ["framework-doc-stubs-default"],
args: metalava_framework_docs_args,
srcs: [
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 1d07a0330bc5..eb8f43e3d073 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -220,8 +220,10 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
String networkId = null;
boolean roaming = !snapshot.getNetworkCapabilities().hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- boolean metered = !snapshot.getNetworkCapabilities().hasCapability(
- NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ boolean metered = !(snapshot.getNetworkCapabilities().hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ || snapshot.getNetworkCapabilities().hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED));
final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index 3db71361610d..69b4187711f6 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -371,6 +371,10 @@ public class UiTranslationController {
Log.v(TAG, "onVirtualViewTranslationCompleted: received response for "
+ "AutofillId " + autofillId);
}
+ view.onVirtualViewTranslationResponses(virtualChildResponse);
+ if (mCurrentState == STATE_UI_TRANSLATION_PAUSED) {
+ return;
+ }
mActivity.runOnUiThread(() -> {
if (view.getViewTranslationCallback() == null) {
if (DEBUG) {
@@ -379,7 +383,6 @@ public class UiTranslationController {
}
return;
}
- view.onVirtualViewTranslationResponses(virtualChildResponse);
if (view.getViewTranslationCallback() != null) {
view.getViewTranslationCallback().onShowTranslation(view);
}
@@ -427,6 +430,8 @@ public class UiTranslationController {
+ " may be gone.");
continue;
}
+ int currentState;
+ currentState = mCurrentState;
mActivity.runOnUiThread(() -> {
ViewTranslationCallback callback = view.getViewTranslationCallback();
if (view.getViewTranslationResponse() != null
@@ -460,6 +465,9 @@ public class UiTranslationController {
callback.enableContentPadding();
}
view.onViewTranslationResponse(response);
+ if (currentState == STATE_UI_TRANSLATION_PAUSED) {
+ return;
+ }
callback.onShowTranslation(view);
});
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 8205d3579b3b..e6f91a25f168 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -128,6 +128,7 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.accessibility.magnification.MagnificationController;
import com.android.server.accessibility.magnification.MagnificationProcessor;
+import com.android.server.accessibility.magnification.MagnificationScaleProvider;
import com.android.server.accessibility.magnification.WindowMagnificationManager;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -338,7 +339,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
mWindowManagerService, this, mSecurityPolicy, this, mTraceManager);
mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
- mMagnificationController = new MagnificationController(this, mLock, mContext);
+ mMagnificationController = new MagnificationController(this, mLock, mContext,
+ new MagnificationScaleProvider(mContext));
mMagnificationProcessor = new MagnificationProcessor(mMagnificationController);
init();
}
@@ -1364,6 +1366,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
private void switchUser(int userId) {
+ mMagnificationController.updateUserIdIfNeeded(userId);
synchronized (mLock) {
if (mCurrentUserId == userId && mInitialized) {
return;
@@ -1386,8 +1389,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// The user changed.
mCurrentUserId = userId;
-
- mMagnificationController.updateUserIdIfNeeded(mCurrentUserId);
AccessibilityUserState userState = getCurrentUserStateLocked();
readConfigurationForUserStateLocked(userState);
@@ -1444,6 +1445,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
synchronized (mLock) {
mUserStates.remove(userId);
}
+ getMagnificationController().onUserRemoved(userId);
}
// Called only during settings restore; currently supports only the owner user
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 8f30aa9acc79..c62473db948c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -28,10 +28,8 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Rect;
import android.graphics.Region;
-import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
-import android.provider.Settings;
import android.text.TextUtils;
import android.util.MathUtils;
import android.util.Slog;
@@ -59,7 +57,8 @@ import java.util.Locale;
* holding the current state of magnification and animation, and it handles
* communication between the accessibility manager and window manager.
*
- * Magnification is limited to the range [MIN_SCALE, MAX_SCALE], and can only occur inside the
+ * Magnification is limited to the range controlled by
+ * {@link MagnificationScaleProvider#constrainScale(float)}, and can only occur inside the
* magnification region. If a value is out of bounds, it will be adjusted to guarantee these
* constraints.
*/
@@ -69,13 +68,9 @@ public class FullScreenMagnificationController {
private static final MagnificationAnimationCallback STUB_ANIMATION_CALLBACK = success -> {
};
- public static final float MIN_SCALE = 1.0f;
- public static final float MAX_SCALE = 8.0f;
private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false;
- private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
-
private final Object mLock;
private final ControllerContext mControllerCtx;
@@ -84,7 +79,7 @@ public class FullScreenMagnificationController {
private final MagnificationInfoChangedCallback mMagnificationInfoChangedCallback;
- private int mUserId;
+ private final MagnificationScaleProvider mScaleProvider;
private final long mMainThreadId;
@@ -489,7 +484,7 @@ public class FullScreenMagnificationController {
return false;
}
// Constrain scale immediately for use in the pivot calculations.
- scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
+ scale = MagnificationScaleProvider.constrainScale(scale);
final Rect viewport = mTempRect;
mMagnificationRegion.getBounds(viewport);
@@ -557,7 +552,7 @@ public class FullScreenMagnificationController {
// Compute changes.
boolean changed = false;
- final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
+ final float normScale = MagnificationScaleProvider.constrainScale(scale);
if (Float.compare(mCurrentMagnificationSpec.scale, normScale) != 0) {
mCurrentMagnificationSpec.scale = normScale;
changed = true;
@@ -658,12 +653,13 @@ public class FullScreenMagnificationController {
*/
public FullScreenMagnificationController(@NonNull Context context,
@NonNull AccessibilityManagerService ams, @NonNull Object lock,
- @NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback) {
+ @NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback,
+ @NonNull MagnificationScaleProvider scaleProvider) {
this(new ControllerContext(context, ams,
LocalServices.getService(WindowManagerInternal.class),
new Handler(context.getMainLooper()),
context.getResources().getInteger(R.integer.config_longAnimTime)), lock,
- magnificationInfoChangedCallback);
+ magnificationInfoChangedCallback, scaleProvider);
}
/**
@@ -672,12 +668,14 @@ public class FullScreenMagnificationController {
@VisibleForTesting
public FullScreenMagnificationController(@NonNull ControllerContext ctx,
@NonNull Object lock,
- @NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback) {
+ @NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback,
+ @NonNull MagnificationScaleProvider scaleProvider) {
mControllerCtx = ctx;
mLock = lock;
mMainThreadId = mControllerCtx.getContext().getMainLooper().getThread().getId();
mScreenStateObserver = new ScreenStateObserver(mControllerCtx.getContext(), this);
mMagnificationInfoChangedCallback = magnificationInfoChangedCallback;
+ mScaleProvider = scaleProvider;
}
/**
@@ -1096,18 +1094,9 @@ public class FullScreenMagnificationController {
/**
* Persists the default display magnification scale to the current user's settings.
*/
- public void persistScale() {
- // TODO: b/123047354, Need support multi-display?
+ public void persistScale(int displayId) {
final float scale = getScale(Display.DEFAULT_DISPLAY);
- final int userId = mUserId;
-
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- mControllerCtx.putMagnificationScale(scale, userId);
- return null;
- }
- }.execute();
+ mScaleProvider.putScale(scale, displayId);
}
/**
@@ -1117,21 +1106,8 @@ public class FullScreenMagnificationController {
* @return the previously persisted magnification scale, or the default
* scale if none is available
*/
- public float getPersistedScale() {
- return mControllerCtx.getMagnificationScale(mUserId);
- }
-
- /**
- * Sets the currently active user ID.
- *
- * @param userId the currently active user ID
- */
- public void setUserId(int userId) {
- if (mUserId == userId) {
- return;
- }
- mUserId = userId;
- resetAllIfNeeded(false);
+ public float getPersistedScale(int displayId) {
+ return mScaleProvider.getScale(displayId);
}
/**
@@ -1225,7 +1201,11 @@ public class FullScreenMagnificationController {
mControllerCtx.getHandler().sendMessage(m);
}
- private void resetAllIfNeeded(boolean animate) {
+ /**
+ * Resets magnification on all displays.
+ * @param animate reset the magnification with animation
+ */
+ void resetAllIfNeeded(boolean animate) {
synchronized (mLock) {
for (int i = 0; i < mDisplays.size(); i++) {
resetIfNeeded(mDisplays.keyAt(i), animate);
@@ -1288,8 +1268,8 @@ public class FullScreenMagnificationController {
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MagnificationController[");
- builder.append("mUserId=").append(mUserId);
builder.append(", mDisplays=").append(mDisplays);
+ builder.append(", mScaleProvider=").append(mScaleProvider);
builder.append("]");
return builder.toString();
}
@@ -1570,23 +1550,6 @@ public class FullScreenMagnificationController {
}
/**
- * Write Settings of magnification scale.
- */
- public void putMagnificationScale(float value, int userId) {
- Settings.Secure.putFloatForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, value, userId);
- }
-
- /**
- * Get Settings of magnification scale.
- */
- public float getMagnificationScale(int userId) {
- return Settings.Secure.getFloatForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
- DEFAULT_MAGNIFICATION_SCALE, userId);
- }
-
- /**
* @return Configuration of animation duration.
*/
public long getAnimationDuration() {
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 8f4a5cb4dad0..935df9934dcb 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -119,11 +119,11 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
private static final boolean DEBUG_DETECTING = false | DEBUG_ALL;
private static final boolean DEBUG_PANNING_SCALING = false | DEBUG_ALL;
- // The MIN_SCALE is different from MagnificationController.MIN_SCALE due
+ // The MIN_SCALE is different from MagnificationScaleProvider.MIN_SCALE due
// to AccessibilityService.MagnificationController#setScale() has
// different scale range
private static final float MIN_SCALE = 2.0f;
- private static final float MAX_SCALE = FullScreenMagnificationController.MAX_SCALE;
+ private static final float MAX_SCALE = MagnificationScaleProvider.MAX_SCALE;
@VisibleForTesting final FullScreenMagnificationController mFullScreenMagnificationController;
@@ -341,7 +341,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
}
public void persistScaleAndTransitionTo(State state) {
- mFullScreenMagnificationController.persistScale();
+ mFullScreenMagnificationController.persistScale(mDisplayId);
clear();
transitionTo(state);
}
@@ -945,7 +945,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
if (DEBUG_DETECTING) Slog.i(mLogTag, "zoomOn(" + centerX + ", " + centerY + ")");
final float scale = MathUtils.constrain(
- mFullScreenMagnificationController.getPersistedScale(),
+ mFullScreenMagnificationController.getPersistedScale(mDisplayId),
MIN_SCALE, MAX_SCALE);
mFullScreenMagnificationController.setScaleAndCenter(mDisplayId,
scale, centerX, centerY,
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 5a6836c2d771..3708c7a422a0 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -23,11 +23,13 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
@@ -75,12 +77,15 @@ public class MagnificationController implements WindowMagnificationManager.Callb
private final SparseArray<DisableMagnificationCallback>
mMagnificationEndRunnableSparseArray = new SparseArray();
+ private final MagnificationScaleProvider mScaleProvider;
private FullScreenMagnificationController mFullScreenMagnificationController;
private WindowMagnificationManager mWindowMagnificationMgr;
private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
@GuardedBy("mLock")
private int mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
+ // Track the active user to reset the magnification and get the associated user settings.
+ private @UserIdInt int mUserId = UserHandle.USER_SYSTEM;
@GuardedBy("mLock")
private boolean mImeWindowVisible = false;
private long mWindowModeEnabledTime = 0;
@@ -98,17 +103,19 @@ public class MagnificationController implements WindowMagnificationManager.Callb
}
public MagnificationController(AccessibilityManagerService ams, Object lock,
- Context context) {
+ Context context, MagnificationScaleProvider scaleProvider) {
mAms = ams;
mLock = lock;
mContext = context;
+ mScaleProvider = scaleProvider;
}
@VisibleForTesting
public MagnificationController(AccessibilityManagerService ams, Object lock,
Context context, FullScreenMagnificationController fullScreenMagnificationController,
- WindowMagnificationManager windowMagnificationManager) {
- this(ams, lock, context);
+ WindowMagnificationManager windowMagnificationManager,
+ MagnificationScaleProvider scaleProvider) {
+ this(ams, lock, context, scaleProvider);
mFullScreenMagnificationController = fullScreenMagnificationController;
mWindowMagnificationMgr = windowMagnificationManager;
}
@@ -194,7 +201,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
final FullScreenMagnificationController screenMagnificationController =
getFullScreenMagnificationController();
final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr();
- final float scale = windowMagnificationMgr.getPersistedScale();
+ final float scale = mScaleProvider.getScale(displayId);
final DisableMagnificationCallback animationEndCallback =
new DisableMagnificationCallback(transitionCallBack, displayId, targetMode,
scale, magnificationCenter);
@@ -313,13 +320,23 @@ public class MagnificationController implements WindowMagnificationManager.Callb
* @param userId the currently active user ID
*/
public void updateUserIdIfNeeded(int userId) {
+ if (mUserId == userId) {
+ return;
+ }
+ mUserId = userId;
+ final FullScreenMagnificationController fullMagnificationController;
+ final WindowMagnificationManager windowMagnificationManager;
synchronized (mLock) {
- if (mFullScreenMagnificationController != null) {
- mFullScreenMagnificationController.setUserId(userId);
- }
- if (mWindowMagnificationMgr != null) {
- mWindowMagnificationMgr.setUserId(userId);
- }
+ fullMagnificationController = mFullScreenMagnificationController;
+ windowMagnificationManager = mWindowMagnificationMgr;
+ }
+
+ mScaleProvider.onUserChanged(userId);
+ if (fullMagnificationController != null) {
+ fullMagnificationController.resetAllIfNeeded(false);
+ }
+ if (windowMagnificationManager != null) {
+ windowMagnificationManager.disableAllWindowMagnifiers();
}
}
@@ -337,6 +354,14 @@ public class MagnificationController implements WindowMagnificationManager.Callb
mWindowMagnificationMgr.onDisplayRemoved(displayId);
}
}
+ mScaleProvider.onDisplayRemoved(displayId);
+ }
+
+ /**
+ * Called when the given user is removed.
+ */
+ public void onUserRemoved(int userId) {
+ mScaleProvider.onUserRemoved(userId);
}
public void setMagnificationCapabilities(int capabilities) {
@@ -378,8 +403,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
synchronized (mLock) {
if (mFullScreenMagnificationController == null) {
mFullScreenMagnificationController = new FullScreenMagnificationController(mContext,
- mAms, mLock, this);
- mFullScreenMagnificationController.setUserId(mAms.getCurrentUserIdLocked());
+ mAms, mLock, this, mScaleProvider);
}
}
return mFullScreenMagnificationController;
@@ -404,7 +428,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb
synchronized (mLock) {
if (mWindowMagnificationMgr == null) {
mWindowMagnificationMgr = new WindowMagnificationManager(mContext,
- mAms.getCurrentUserIdLocked(), this, mAms.getTraceManager());
+ mUserId, this, mAms.getTraceManager(),
+ mScaleProvider);
}
return mWindowMagnificationMgr;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationScaleProvider.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationScaleProvider.java
new file mode 100644
index 000000000000..8e1aa38be9e8
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationScaleProvider.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility.magnification;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.MathUtils;
+import android.util.SparseArray;
+import android.view.Display;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+
+/**
+ * Supplies setter/getter of the magnification scale for the given display. Only the value of the
+ * default play is persisted. It also constraints the range of applied magnification scale between
+ * [MIN_SCALE, MAX_SCALE] which is consistent with the range provided by
+ * {@code AccessibilityService.MagnificationController#setScale()}.
+ */
+public class MagnificationScaleProvider {
+
+ @VisibleForTesting
+ protected static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
+ public static final float MIN_SCALE = 1.0f;
+ public static final float MAX_SCALE = 8.0f;
+
+ private final Context mContext;
+ // Stores the scale for non-default displays.
+ @GuardedBy("mLock")
+ private final SparseArray<SparseArray<Float>> mUsersScales = new SparseArray();
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
+ private final Object mLock = new Object();
+
+ public MagnificationScaleProvider(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Stores the user settings scale associated to the given display. Only the scale of the
+ * default display is persistent.
+ *
+ * @param scale the magnification scale
+ * @param displayId the id of the display
+ */
+ void putScale(float scale, int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ BackgroundThread.getHandler().post(
+ () -> Settings.Secure.putFloatForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale,
+ mCurrentUserId));
+ } else {
+ synchronized (mLock) {
+ getScalesWithCurrentUser().put(displayId, scale);
+ }
+ }
+ }
+
+ /**
+ * Gets the user settings scale with the given display.
+ *
+ * @param displayId the id of the display
+ * @return the magnification scale.
+ */
+ float getScale(int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ return Settings.Secure.getFloatForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+ DEFAULT_MAGNIFICATION_SCALE, mCurrentUserId);
+ } else {
+ synchronized (mLock) {
+ return getScalesWithCurrentUser().get(displayId, DEFAULT_MAGNIFICATION_SCALE);
+ }
+ }
+ }
+
+
+ @GuardedBy("mLock")
+ private SparseArray<Float> getScalesWithCurrentUser() {
+ SparseArray<Float> scales = mUsersScales.get(mCurrentUserId);
+ if (scales == null) {
+ scales = new SparseArray<>();
+ mUsersScales.put(mCurrentUserId, scales);
+ }
+
+ return scales;
+ }
+
+ void onUserChanged(int userId) {
+ synchronized (mLock) {
+ mCurrentUserId = userId;
+ }
+ }
+
+ void onUserRemoved(int userId) {
+ synchronized (mLock) {
+ mUsersScales.remove(userId);
+ }
+ }
+
+ void onDisplayRemoved(int displayId) {
+ synchronized (mLock) {
+ final int userCounts = mUsersScales.size();
+ for (int i = userCounts - 1; i >= 0; i--) {
+ mUsersScales.get(i).remove(displayId);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ synchronized (mLock) {
+ return "MagnificationScaleProvider{"
+ + "mCurrentUserId=" + mCurrentUserId
+ + "Scale on the default display=" + getScale(Display.DEFAULT_DISPLAY)
+ + "Scales on non-default displays=" + getScalesWithCurrentUser()
+ + '}';
+ }
+ }
+
+ static float constrainScale(float scale) {
+ return MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index bc61284f6084..7d8f545b65c3 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -69,7 +69,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
//Ensure the range has consistency with FullScreenMagnificationGestureHandler.
private static final float MIN_SCALE = 2.0f;
- private static final float MAX_SCALE = WindowMagnificationManager.MAX_SCALE;
+ private static final float MAX_SCALE = MagnificationScaleProvider.MAX_SCALE;
private final WindowMagnificationManager mWindowMagnificationMgr;
@VisibleForTesting
@@ -177,8 +177,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
}
final float scale = MathUtils.constrain(
- mWindowMagnificationMgr.getPersistedScale(),
- MIN_SCALE, MAX_SCALE);
+ mWindowMagnificationMgr.getPersistedScale(mDisplayId), MIN_SCALE, MAX_SCALE);
mWindowMagnificationMgr.enableWindowMagnification(mDisplayId, scale, centerX, centerY);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index 7a111d80b42e..ce7ba7568b6e 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -29,8 +29,6 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.view.MotionEvent;
@@ -40,7 +38,6 @@ import android.view.accessibility.MagnificationAnimationCallback;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -49,6 +46,8 @@ import com.android.server.statusbar.StatusBarManagerInternal;
* A class to manipulate window magnification through {@link WindowMagnificationConnectionWrapper}
* create by {@link #setConnection(IWindowMagnificationConnection)}. To set the connection with
* SysUI, call {@code StatusBarManagerInternal#requestWindowMagnificationConnection(boolean)}.
+ * The applied magnification scale is constrained by
+ * {@link MagnificationScaleProvider#constrainScale(float)}
*/
public class WindowMagnificationManager implements
PanningScalingHandler.MagnificationDelegate {
@@ -57,10 +56,6 @@ public class WindowMagnificationManager implements
private static final String TAG = "WindowMagnificationMgr";
- //Ensure the range has consistency with full screen.
- static final float MAX_SCALE = FullScreenMagnificationController.MAX_SCALE;
- static final float MIN_SCALE = FullScreenMagnificationController.MIN_SCALE;
-
private final Object mLock = new Object();
private final Context mContext;
@VisibleForTesting
@@ -71,7 +66,6 @@ public class WindowMagnificationManager implements
private ConnectionCallback mConnectionCallback;
@GuardedBy("mLock")
private SparseArray<WindowMagnifier> mWindowMagnifiers = new SparseArray<>();
- private int mUserId;
private boolean mReceiverRegistered = false;
@VisibleForTesting
@@ -116,13 +110,14 @@ public class WindowMagnificationManager implements
private final Callback mCallback;
private final AccessibilityTraceManager mTrace;
+ private final MagnificationScaleProvider mScaleProvider;
public WindowMagnificationManager(Context context, int userId, @NonNull Callback callback,
- AccessibilityTraceManager trace) {
+ AccessibilityTraceManager trace, MagnificationScaleProvider scaleProvider) {
mContext = context;
- mUserId = userId;
mCallback = callback;
mTrace = trace;
+ mScaleProvider = scaleProvider;
}
/**
@@ -159,15 +154,6 @@ public class WindowMagnificationManager implements
}
/**
- * Sets the currently active user ID.
- *
- * @param userId the currently active user ID
- */
- public void setUserId(int userId) {
- mUserId = userId;
- }
-
- /**
* @return {@code true} if {@link IWindowMagnificationConnection} is available
*/
public boolean isConnected() {
@@ -219,13 +205,18 @@ public class WindowMagnificationManager implements
return true;
}
- @GuardedBy("mLock")
- private void disableAllWindowMagnifiers() {
- for (int i = 0; i < mWindowMagnifiers.size(); i++) {
- final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i);
- magnifier.disableWindowMagnificationInternal(null);
+ /**
+ * Disables window magnifier on all displays without animation.
+ */
+ void disableAllWindowMagnifiers() {
+ synchronized (mLock) {
+ for (int i = 0; i < mWindowMagnifiers.size(); i++) {
+ final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i);
+ magnifier.disableWindowMagnificationInternal(null);
+ }
+ mWindowMagnifiers.clear();
}
- mWindowMagnifiers.clear();
+
}
private void resetWindowMagnifiers() {
@@ -378,29 +369,24 @@ public class WindowMagnificationManager implements
}
/**
- * Retrieves a previously persisted magnification scale from the current
- * user's settings.
+ * Retrieves a previously magnification scale from the current
+ * user's settings. Only the value of the default display is persisted.
*
- * @return the previously persisted magnification scale, or the default
+ * @return the previously magnification scale, or the default
* scale if none is available
*/
- float getPersistedScale() {
- return Settings.Secure.getFloatForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
- MIN_SCALE, mUserId);
+ float getPersistedScale(int displayId) {
+ return mScaleProvider.getScale(displayId);
}
/**
- * Persists the default display magnification scale to the current user's settings.
+ * Persists the default display magnification scale to the current user's settings. Only the
+ * value of the default display is persisted in user's settings.
*/
void persistScale(int displayId) {
-
float scale = getScale(displayId);
if (scale != 1.0f) {
- BackgroundThread.getHandler().post(() -> {
- Settings.Secure.putFloatForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale, mUserId);
- });
+ mScaleProvider.putScale(scale, displayId);
}
}
@@ -511,7 +497,7 @@ public class WindowMagnificationManager implements
*
* @param displayId The logical display id.
*/
- void onDisplayRemoved(int displayId) {
+ public void onDisplayRemoved(int displayId) {
disableWindowMagnification(displayId, true);
}
@@ -613,7 +599,7 @@ public class WindowMagnificationManager implements
private static class WindowMagnifier {
private final int mDisplayId;
- private float mScale = MIN_SCALE;
+ private float mScale = MagnificationScaleProvider.MIN_SCALE;
private boolean mEnabled;
private final WindowMagnificationManager mWindowMagnificationManager;
@@ -633,7 +619,7 @@ public class WindowMagnificationManager implements
if (mEnabled) {
return false;
}
- final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
+ final float normScale = MagnificationScaleProvider.constrainScale(scale);
if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale,
centerX, centerY, animationCallback)) {
mScale = normScale;
@@ -664,7 +650,7 @@ public class WindowMagnificationManager implements
if (!mEnabled) {
return;
}
- final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
+ final float normScale = MagnificationScaleProvider.constrainScale(scale);
if (Float.compare(mScale, normScale) != 0
&& mWindowMagnificationManager.setScaleInternal(mDisplayId, scale)) {
mScale = normScale;
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
new file mode 100644
index 000000000000..2a0adeb71559
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion;
+
+import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static com.android.internal.util.CollectionUtils.filter;
+import static com.android.internal.util.FunctionalUtils.uncheckExceptions;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.server.companion.CompanionDeviceManagerService.DEBUG;
+import static com.android.server.companion.CompanionDeviceManagerService.LOG_TAG;
+import static com.android.server.companion.CompanionDeviceManagerService.getCallingUserId;
+
+import static java.util.Collections.unmodifiableMap;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.companion.Association;
+import android.companion.AssociationRequest;
+import android.companion.CompanionDeviceManager;
+import android.companion.ICompanionDeviceDiscoveryService;
+import android.companion.IFindDeviceCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.Signature;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.PackageUtils;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.PerUser;
+import com.android.internal.infra.ServiceConnector;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.FgThread;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+class AssociationRequestsProcessor {
+ private static final String TAG = LOG_TAG + ".AssociationRequestsProcessor";
+
+ private static final Map<String, String> DEVICE_PROFILE_TO_PERMISSION;
+ static {
+ final Map<String, String> map = new ArrayMap<>();
+ map.put(DEVICE_PROFILE_WATCH, Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH);
+ map.put(DEVICE_PROFILE_APP_STREAMING,
+ Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING);
+
+ DEVICE_PROFILE_TO_PERMISSION = unmodifiableMap(map);
+ }
+
+ private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
+ CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
+ ".CompanionDeviceDiscoveryService");
+
+ private static final int ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW = 5;
+ private static final long ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS = 60 * 60 * 1000; // 60 min;
+
+ private final Context mContext;
+ private final CompanionDeviceManagerService mService;
+
+ private AssociationRequest mRequest;
+ private IFindDeviceCallback mFindDeviceCallback;
+ private String mCallingPackage;
+ private AndroidFuture<?> mOngoingDeviceDiscovery;
+
+ private PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>> mServiceConnectors;
+
+ AssociationRequestsProcessor(CompanionDeviceManagerService service) {
+ mContext = service.getContext();
+ mService = service;
+
+ final Intent serviceIntent = new Intent().setComponent(SERVICE_TO_BIND_TO);
+ mServiceConnectors = new PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>>() {
+ @Override
+ protected ServiceConnector<ICompanionDeviceDiscoveryService> create(int userId) {
+ return new ServiceConnector.Impl<>(
+ mContext,
+ serviceIntent, 0/* bindingFlags */, userId,
+ ICompanionDeviceDiscoveryService.Stub::asInterface);
+ }
+ };
+ }
+
+ void process(AssociationRequest request, IFindDeviceCallback callback, String callingPackage)
+ throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "process(request=" + request + ", from=" + callingPackage + ")");
+ }
+
+ checkNotNull(request, "Request cannot be null");
+ checkNotNull(callback, "Callback cannot be null");
+ mService.checkCallerIsSystemOr(callingPackage);
+ int userId = getCallingUserId();
+ mService.checkUsesFeature(callingPackage, userId);
+ final String deviceProfile = request.getDeviceProfile();
+ validateDeviceProfileAndCheckPermission(deviceProfile);
+
+ mFindDeviceCallback = callback;
+ mRequest = request;
+ mCallingPackage = callingPackage;
+ request.setCallingPackage(callingPackage);
+
+ if (mayAssociateWithoutPrompt(callingPackage, userId)) {
+ Slog.i(TAG, "setSkipPrompt(true)");
+ request.setSkipPrompt(true);
+ }
+ callback.asBinder().linkToDeath(mBinderDeathRecipient /* recipient */, 0);
+
+ mOngoingDeviceDiscovery = getDeviceProfilePermissionDescription(deviceProfile)
+ .thenComposeAsync(description -> {
+ if (DEBUG) {
+ Slog.d(TAG, "fetchProfileDescription done: " + description);
+ }
+
+ request.setDeviceProfilePrivilegesDescription(description);
+
+ return mServiceConnectors.forUser(userId).postAsync(service -> {
+ if (DEBUG) {
+ Slog.d(TAG, "Connected to CDM service -> "
+ + "Starting discovery for " + request);
+ }
+
+ AndroidFuture<String> future = new AndroidFuture<>();
+ service.startDiscovery(request, callingPackage, callback, future);
+ return future;
+ }).cancelTimeout();
+
+ }, FgThread.getExecutor()).whenComplete(uncheckExceptions((deviceAddress, err) -> {
+ if (err == null) {
+ mService.createAssociationInternal(
+ userId, deviceAddress, callingPackage, deviceProfile);
+ } else {
+ Slog.e(TAG, "Failed to discover device(s)", err);
+ callback.onFailure("No devices found: " + err.getMessage());
+ }
+ cleanup();
+ }));
+ }
+
+ void stopScan(AssociationRequest request, IFindDeviceCallback callback, String callingPackage) {
+ if (DEBUG) {
+ Slog.d(TAG, "stopScan(request = " + request + ")");
+ }
+ if (Objects.equals(request, mRequest)
+ && Objects.equals(callback, mFindDeviceCallback)
+ && Objects.equals(callingPackage, mCallingPackage)) {
+ cleanup();
+ }
+ }
+
+ private void validateDeviceProfileAndCheckPermission(@Nullable String deviceProfile) {
+ // Device profile can be null.
+ if (deviceProfile == null) return;
+
+ if (DEVICE_PROFILE_APP_STREAMING.equals(deviceProfile)) {
+ // TODO: remove, when properly supporting this profile.
+ throw new UnsupportedOperationException(
+ "DEVICE_PROFILE_APP_STREAMING is not fully supported yet.");
+ }
+
+ if (!DEVICE_PROFILE_TO_PERMISSION.containsKey(deviceProfile)) {
+ throw new IllegalArgumentException("Unsupported device profile: " + deviceProfile);
+ }
+
+ final String permission = DEVICE_PROFILE_TO_PERMISSION.get(deviceProfile);
+ if (mContext.checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
+ throw new SecurityException("Application must hold " + permission + " to associate "
+ + "with a device with " + deviceProfile + " profile.");
+ }
+ }
+
+ private void cleanup() {
+ if (DEBUG) {
+ Slog.d(TAG, "cleanup(); discovery = "
+ + mOngoingDeviceDiscovery + ", request = " + mRequest);
+ }
+ synchronized (mService.mLock) {
+ AndroidFuture<?> ongoingDeviceDiscovery = mOngoingDeviceDiscovery;
+ if (ongoingDeviceDiscovery != null && !ongoingDeviceDiscovery.isDone()) {
+ ongoingDeviceDiscovery.cancel(true);
+ }
+ if (mFindDeviceCallback != null) {
+ mFindDeviceCallback.asBinder().unlinkToDeath(mBinderDeathRecipient, 0);
+ mFindDeviceCallback = null;
+ }
+ mRequest = null;
+ mCallingPackage = null;
+ }
+ }
+
+ private boolean mayAssociateWithoutPrompt(String packageName, int userId) {
+ String[] sameOemPackages = mContext.getResources()
+ .getStringArray(com.android.internal.R.array.config_companionDevicePackages);
+ if (!ArrayUtils.contains(sameOemPackages, packageName)) {
+ Slog.w(TAG, packageName
+ + " can not silently create associations due to no package found."
+ + " Packages from OEM: " + Arrays.toString(sameOemPackages)
+ );
+ return false;
+ }
+
+ // Throttle frequent associations
+ long now = System.currentTimeMillis();
+ Set<Association> recentAssociations = filter(
+ mService.getAllAssociations(userId, packageName),
+ a -> now - a.getTimeApprovedMs() < ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS);
+
+ if (recentAssociations.size() >= ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW) {
+ Slog.w(TAG, "Too many associations. " + packageName
+ + " already associated " + recentAssociations.size()
+ + " devices within the last " + ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS
+ + "ms: " + recentAssociations);
+ return false;
+ }
+ String[] sameOemCerts = mContext.getResources()
+ .getStringArray(com.android.internal.R.array.config_companionDeviceCerts);
+
+ Signature[] signatures = mService.mPackageManagerInternal
+ .getPackage(packageName).getSigningDetails().getSignatures();
+ String[] apkCerts = PackageUtils.computeSignaturesSha256Digests(signatures);
+
+ Set<String> sameOemPackageCerts =
+ getSameOemPackageCerts(packageName, sameOemPackages, sameOemCerts);
+
+ for (String cert : apkCerts) {
+ if (sameOemPackageCerts.contains(cert)) {
+ return true;
+ }
+ }
+
+ Slog.w(TAG, packageName
+ + " can not silently create associations. " + packageName
+ + " has SHA256 certs from APK: " + Arrays.toString(apkCerts)
+ + " and from OEM: " + Arrays.toString(sameOemCerts)
+ );
+
+ return false;
+ }
+
+ @NonNull
+ private AndroidFuture<String> getDeviceProfilePermissionDescription(
+ @Nullable String deviceProfile) {
+ if (deviceProfile == null) {
+ return AndroidFuture.completedFuture(null);
+ }
+
+ final AndroidFuture<String> result = new AndroidFuture<>();
+ mService.mPermissionControllerManager.getPrivilegesDescriptionStringForProfile(
+ deviceProfile, FgThread.getExecutor(), desc -> {
+ try {
+ result.complete(String.valueOf(desc));
+ } catch (Exception e) {
+ result.completeExceptionally(e);
+ }
+ });
+ return result;
+ }
+
+
+ void dump(@NonNull PrintWriter pw) {
+ pw.append("Discovery Service State:").append('\n');
+ for (int i = 0, size = mServiceConnectors.size(); i < size; i++) {
+ int userId = mServiceConnectors.keyAt(i);
+ pw.append(" ")
+ .append("u").append(Integer.toString(userId)).append(": ")
+ .append(Objects.toString(mServiceConnectors.valueAt(i)))
+ .append('\n');
+ }
+ }
+
+ private final IBinder.DeathRecipient mBinderDeathRecipient = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ if (DEBUG) {
+ Slog.d(TAG, "binderDied()");
+ }
+ mService.mMainHandler.post(AssociationRequestsProcessor.this::cleanup);
+ }
+ };
+
+ private static Set<String> getSameOemPackageCerts(
+ String packageName, String[] oemPackages, String[] sameOemCerts) {
+ Set<String> sameOemPackageCerts = new HashSet<>();
+
+ // Assume OEM may enter same package name in the parallel string array with
+ // multiple APK certs corresponding to it
+ for (int i = 0; i < oemPackages.length; i++) {
+ if (oemPackages[i].equals(packageName)) {
+ sameOemPackageCerts.add(sameOemCerts[i].replaceAll(":", ""));
+ }
+ }
+
+ return sameOemPackageCerts;
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index a48172bff4df..ad4c35c2e755 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -19,8 +19,6 @@ package com.android.server.companion;
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
-import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
-import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static android.companion.DeviceId.TYPE_MAC_ADDRESS;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -31,7 +29,6 @@ import static com.android.internal.util.CollectionUtils.filter;
import static com.android.internal.util.CollectionUtils.find;
import static com.android.internal.util.CollectionUtils.forEach;
import static com.android.internal.util.CollectionUtils.map;
-import static com.android.internal.util.FunctionalUtils.uncheckExceptions;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
@@ -39,13 +36,10 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa
import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
import static java.util.Collections.emptySet;
-import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableSet;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MINUTES;
-import android.Manifest;
-import android.annotation.CheckResult;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -64,10 +58,8 @@ import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.companion.Association;
import android.companion.AssociationRequest;
-import android.companion.CompanionDeviceManager;
import android.companion.DeviceId;
import android.companion.DeviceNotAssociatedException;
-import android.companion.ICompanionDeviceDiscoveryService;
import android.companion.ICompanionDeviceManager;
import android.companion.IFindDeviceCallback;
import android.content.BroadcastReceiver;
@@ -81,14 +73,11 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.net.NetworkPolicyManager;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
-import android.os.IBinder;
-import android.os.IInterface;
import android.os.Parcel;
import android.os.PowerWhitelistManager;
import android.os.Process;
@@ -103,7 +92,6 @@ import android.text.BidiFormatter;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ExceptionUtils;
-import android.util.PackageUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -111,9 +99,6 @@ import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.infra.AndroidFuture;
-import com.android.internal.infra.PerUser;
-import com.android.internal.infra.ServiceConnector;
import com.android.internal.notification.NotificationAccessConfirmationActivityContract;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
@@ -146,27 +131,13 @@ import java.util.function.Predicate;
/** @hide */
@SuppressLint("LongLogTag")
-public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient {
+public class CompanionDeviceManagerService extends SystemService {
static final String LOG_TAG = "CompanionDeviceManagerService";
static final boolean DEBUG = false;
- private static final Map<String, String> DEVICE_PROFILE_TO_PERMISSION;
- static {
- final Map<String, String> map = new ArrayMap<>();
- map.put(DEVICE_PROFILE_WATCH, Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH);
- map.put(DEVICE_PROFILE_APP_STREAMING,
- Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING);
-
- DEVICE_PROFILE_TO_PERMISSION = unmodifiableMap(map);
- }
-
/** Range of Association IDs allocated for a user.*/
static final int ASSOCIATIONS_IDS_PER_USER_RANGE = 100000;
- private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
- CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
- ".CompanionDeviceDiscoveryService");
-
private static final long DEVICE_DISAPPEARED_TIMEOUT_MS = 10 * 1000;
private static final long DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS = 10 * 60 * 1000;
@@ -177,9 +148,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
private static final String PREF_FILE_NAME = "companion_device_preferences.xml";
private static final String PREF_KEY_AUTO_REVOKE_GRANTS_DONE = "auto_revoke_grants_done";
- private static final int ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW = 5;
- private static final long ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS = 60 * 60 * 1000; // 60 min;
-
private static DateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
static {
sDateFormat.setTimeZone(TimeZone.getDefault());
@@ -188,19 +156,15 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
private final CompanionDeviceManagerImpl mImpl;
// Persistent data store for all Associations.
private final PersistentDataStore mPersistentDataStore;
+ private final AssociationRequestsProcessor mAssociationRequestsProcessor;
private PowerWhitelistManager mPowerWhitelistManager;
- private PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>> mServiceConnectors;
private IAppOpsService mAppOpsManager;
private RoleManager mRoleManager;
private BluetoothAdapter mBluetoothAdapter;
private UserManager mUserManager;
- private IFindDeviceCallback mFindDeviceCallback;
private ScanCallback mBleScanCallback = new BleScanCallback();
- private AssociationRequest mRequest;
- private String mCallingPackage;
- private AndroidFuture<?> mOngoingDeviceDiscovery;
- private PermissionControllerManager mPermissionControllerManager;
+ PermissionControllerManager mPermissionControllerManager;
private BluetoothDeviceConnectedListener mBluetoothDeviceConnectedListener =
new BluetoothDeviceConnectedListener();
@@ -212,8 +176,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
private ArrayMap<String, TriggerDeviceDisappearedRunnable> mTriggerDeviceDisappearedRunnables =
new ArrayMap<>();
- private final Object mLock = new Object();
- private final Handler mMainHandler = Handler.getMain();
+ final Object mLock = new Object();
+ final Handler mMainHandler = Handler.getMain();
private CompanionDevicePresenceController mCompanionDevicePresenceController;
/** Maps a {@link UserIdInt} to a set of associations for the user. */
@@ -236,6 +200,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
super(context);
mImpl = new CompanionDeviceManagerImpl();
mPersistentDataStore = new PersistentDataStore();
+ mAssociationRequestsProcessor = new AssociationRequestsProcessor(this);
mPowerWhitelistManager = context.getSystemService(PowerWhitelistManager.class);
mRoleManager = context.getSystemService(RoleManager.class);
@@ -249,17 +214,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
mUserManager = context.getSystemService(UserManager.class);
mCompanionDevicePresenceController = new CompanionDevicePresenceController();
- Intent serviceIntent = new Intent().setComponent(SERVICE_TO_BIND_TO);
- mServiceConnectors = new PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>>() {
- @Override
- protected ServiceConnector<ICompanionDeviceDiscoveryService> create(int userId) {
- return new ServiceConnector.Impl<>(
- getContext(),
- serviceIntent, 0/* bindingFlags */, userId,
- ICompanionDeviceDiscoveryService.Stub::asInterface);
- }
- };
-
registerPackageMonitor();
}
@@ -357,39 +311,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
}
- @Override
- public void binderDied() {
- Slog.w(LOG_TAG, "binderDied()");
- mMainHandler.post(this::cleanup);
- }
-
- private void cleanup() {
- Slog.d(LOG_TAG, "cleanup(); discovery = "
- + mOngoingDeviceDiscovery + ", request = " + mRequest);
- synchronized (mLock) {
- AndroidFuture<?> ongoingDeviceDiscovery = mOngoingDeviceDiscovery;
- if (ongoingDeviceDiscovery != null && !ongoingDeviceDiscovery.isDone()) {
- ongoingDeviceDiscovery.cancel(true);
- }
- mFindDeviceCallback = unlinkToDeath(mFindDeviceCallback, this, 0);
- mRequest = null;
- mCallingPackage = null;
- }
- }
-
- /**
- * Usage: {@code a = unlinkToDeath(a, deathRecipient, flags); }
- */
- @Nullable
- @CheckResult
- private static <T extends IInterface> T unlinkToDeath(T iinterface,
- IBinder.DeathRecipient deathRecipient, int flags) {
- if (iinterface != null) {
- iinterface.asBinder().unlinkToDeath(deathRecipient, flags);
- }
- return null;
- }
-
class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
@Override
@@ -410,61 +331,15 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
String callingPackage) throws RemoteException {
Slog.i(LOG_TAG, "associate(request = " + request + ", callback = " + callback
+ ", callingPackage = " + callingPackage + ")");
- checkNotNull(request, "Request cannot be null");
- checkNotNull(callback, "Callback cannot be null");
- checkCallerIsSystemOr(callingPackage);
- int userId = getCallingUserId();
- checkUsesFeature(callingPackage, userId);
- final String deviceProfile = request.getDeviceProfile();
- validateDeviceProfileAndCheckPermission(deviceProfile);
-
- mFindDeviceCallback = callback;
- mRequest = request;
- mCallingPackage = callingPackage;
- request.setCallingPackage(callingPackage);
-
- if (mayAssociateWithoutPrompt(callingPackage, userId)) {
- Slog.i(LOG_TAG, "setSkipPrompt(true)");
- request.setSkipPrompt(true);
- }
- callback.asBinder().linkToDeath(CompanionDeviceManagerService.this /* recipient */, 0);
-
- mOngoingDeviceDiscovery = getDeviceProfilePermissionDescription(deviceProfile)
- .thenComposeAsync(description -> {
- Slog.d(LOG_TAG, "fetchProfileDescription done: " + description);
-
- request.setDeviceProfilePrivilegesDescription(description);
-
- return mServiceConnectors.forUser(userId).postAsync(service -> {
- Slog.d(LOG_TAG, "Connected to CDM service; starting discovery for " + request);
-
- AndroidFuture<String> future = new AndroidFuture<>();
- service.startDiscovery(request, callingPackage, callback, future);
- return future;
- }).cancelTimeout();
-
- }, FgThread.getExecutor()).whenComplete(uncheckExceptions((deviceAddress, err) -> {
- if (err == null) {
- createAssociationInternal(
- userId, deviceAddress, callingPackage, deviceProfile);
- } else {
- Slog.e(LOG_TAG, "Failed to discover device(s)", err);
- callback.onFailure("No devices found: " + err.getMessage());
- }
- cleanup();
- }));
+ mAssociationRequestsProcessor.process(request, callback, callingPackage);
}
@Override
public void stopScan(AssociationRequest request,
IFindDeviceCallback callback,
String callingPackage) {
- Slog.d(LOG_TAG, "stopScan(request = " + request + ")");
- if (Objects.equals(request, mRequest)
- && Objects.equals(callback, mFindDeviceCallback)
- && Objects.equals(callingPackage, mCallingPackage)) {
- cleanup();
- }
+ Slog.i(LOG_TAG, "stopScan(request = " + request + ")");
+ mAssociationRequestsProcessor.stopScan(request, callback, callingPackage);
}
@Override
@@ -505,44 +380,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
== PERMISSION_GRANTED;
}
- private void checkCallerIsSystemOr(String pkg) throws RemoteException {
- checkCallerIsSystemOr(pkg, getCallingUserId());
- }
-
- private void checkCallerIsSystemOr(String pkg, int userId) throws RemoteException {
- if (isCallerSystem()) {
- return;
- }
-
- checkArgument(getCallingUserId() == userId,
- "Must be called by either same user or system");
- int callingUid = Binder.getCallingUid();
- if (mAppOpsManager.checkPackage(callingUid, pkg) != AppOpsManager.MODE_ALLOWED) {
- throw new SecurityException(pkg + " doesn't belong to uid " + callingUid);
- }
- }
-
- private void validateDeviceProfileAndCheckPermission(@Nullable String deviceProfile) {
- // Device profile can be null.
- if (deviceProfile == null) return;
-
- if (DEVICE_PROFILE_APP_STREAMING.equals(deviceProfile)) {
- // TODO: remove, when properly supporting this profile.
- throw new UnsupportedOperationException(
- "DEVICE_PROFILE_APP_STREAMING is not fully supported yet.");
- }
-
- if (!DEVICE_PROFILE_TO_PERMISSION.containsKey(deviceProfile)) {
- throw new IllegalArgumentException("Unsupported device profile: " + deviceProfile);
- }
-
- final String permission = DEVICE_PROFILE_TO_PERMISSION.get(deviceProfile);
- if (getContext().checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
- throw new SecurityException("Application must hold " + permission + " to associate "
- + "with a device with " + deviceProfile + " profile.");
- }
- }
-
@Override
public PendingIntent requestNotificationAccess(ComponentName component)
throws RemoteException {
@@ -674,23 +511,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
checkUsesFeature(callingPackage, userId);
}
- private void checkUsesFeature(String pkg, int userId) {
- if (isCallerSystem()) {
- // Drop the requirement for calls from system process
- return;
- }
-
- FeatureInfo[] reqFeatures = getPackageInfo(pkg, userId).reqFeatures;
- String requiredFeature = PackageManager.FEATURE_COMPANION_DEVICE_SETUP;
- int numFeatures = ArrayUtils.size(reqFeatures);
- for (int i = 0; i < numFeatures; i++) {
- if (requiredFeature.equals(reqFeatures[i].name)) return;
- }
- throw new IllegalStateException("Must declare uses-feature "
- + requiredFeature
- + " in manifest to use this API");
- }
-
@Override
public boolean canPairWithoutPrompt(
String packageName, String deviceMacAddress, int userId) {
@@ -740,14 +560,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
.append(sDateFormat.format(time)).append('\n');
}
- fout.append("Discovery Service State:").append('\n');
- for (int i = 0, size = mServiceConnectors.size(); i < size; i++) {
- int userId = mServiceConnectors.keyAt(i);
- fout.append(" ")
- .append("u").append(Integer.toString(userId)).append(": ")
- .append(Objects.toString(mServiceConnectors.valueAt(i)))
- .append('\n');
- }
+ mAssociationRequestsProcessor.dump(fout);
fout.append("Device Listener Services State:").append('\n');
for (int i = 0, size = mCompanionDevicePresenceController.mBoundServices.size();
@@ -762,7 +575,24 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
}
- private static int getCallingUserId() {
+ void checkCallerIsSystemOr(String pkg) throws RemoteException {
+ checkCallerIsSystemOr(pkg, getCallingUserId());
+ }
+
+ private void checkCallerIsSystemOr(String pkg, int userId) throws RemoteException {
+ if (isCallerSystem()) {
+ return;
+ }
+
+ checkArgument(getCallingUserId() == userId,
+ "Must be called by either same user or system");
+ int callingUid = Binder.getCallingUid();
+ if (mAppOpsManager.checkPackage(callingUid, pkg) != AppOpsManager.MODE_ALLOWED) {
+ throw new SecurityException(pkg + " doesn't belong to uid " + callingUid);
+ }
+ }
+
+ static int getCallingUserId() {
return UserHandle.getUserId(Binder.getCallingUid());
}
@@ -770,6 +600,23 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
return Binder.getCallingUid() == Process.SYSTEM_UID;
}
+ void checkUsesFeature(String pkg, int userId) {
+ if (isCallerSystem()) {
+ // Drop the requirement for calls from system process
+ return;
+ }
+
+ FeatureInfo[] reqFeatures = getPackageInfo(pkg, userId).reqFeatures;
+ String requiredFeature = PackageManager.FEATURE_COMPANION_DEVICE_SETUP;
+ int numFeatures = ArrayUtils.size(reqFeatures);
+ for (int i = 0; i < numFeatures; i++) {
+ if (requiredFeature.equals(reqFeatures[i].name)) return;
+ }
+ throw new IllegalStateException("Must declare uses-feature "
+ + requiredFeature
+ + " in manifest to use this API");
+ }
+
void createAssociationInternal(
int userId, String deviceMacAddress, String packageName, String deviceProfile) {
final Association association = new Association(
@@ -950,72 +797,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
}
- private Set<String> getSameOemPackageCerts(
- String packageName, String[] oemPackages, String[] sameOemCerts) {
- Set<String> sameOemPackageCerts = new HashSet<>();
-
- // Assume OEM may enter same package name in the parallel string array with
- // multiple APK certs corresponding to it
- for (int i = 0; i < oemPackages.length; i++) {
- if (oemPackages[i].equals(packageName)) {
- sameOemPackageCerts.add(sameOemCerts[i].replaceAll(":", ""));
- }
- }
-
- return sameOemPackageCerts;
- }
-
- boolean mayAssociateWithoutPrompt(String packageName, int userId) {
- String[] sameOemPackages = getContext()
- .getResources()
- .getStringArray(com.android.internal.R.array.config_companionDevicePackages);
- if (!ArrayUtils.contains(sameOemPackages, packageName)) {
- Slog.w(LOG_TAG, packageName
- + " can not silently create associations due to no package found."
- + " Packages from OEM: " + Arrays.toString(sameOemPackages)
- );
- return false;
- }
-
- // Throttle frequent associations
- long now = System.currentTimeMillis();
- Set<Association> recentAssociations = filter(
- getAllAssociations(userId, packageName),
- a -> now - a.getTimeApprovedMs() < ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS);
-
- if (recentAssociations.size() >= ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW) {
- Slog.w(LOG_TAG, "Too many associations. " + packageName
- + " already associated " + recentAssociations.size()
- + " devices within the last " + ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS
- + "ms: " + recentAssociations);
- return false;
- }
- String[] sameOemCerts = getContext()
- .getResources()
- .getStringArray(com.android.internal.R.array.config_companionDeviceCerts);
-
- Signature[] signatures = mPackageManagerInternal
- .getPackage(packageName).getSigningDetails().getSignatures();
- String[] apkCerts = PackageUtils.computeSignaturesSha256Digests(signatures);
-
- Set<String> sameOemPackageCerts =
- getSameOemPackageCerts(packageName, sameOemPackages, sameOemCerts);
-
- for (String cert : apkCerts) {
- if (sameOemPackageCerts.contains(cert)) {
- return true;
- }
- }
-
- Slog.w(LOG_TAG, packageName
- + " can not silently create associations. " + packageName
- + " has SHA256 certs from APK: " + Arrays.toString(apkCerts)
- + " and from OEM: " + Arrays.toString(sameOemCerts)
- );
-
- return false;
- }
-
private static <T> boolean containsEither(T[] array, T a, T b) {
return ArrayUtils.contains(array, a) || ArrayUtils.contains(array, b);
}
@@ -1120,7 +901,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
}
- private Set<Association> getAllAssociations(int userId, @Nullable String packageFilter) {
+ Set<Association> getAllAssociations(int userId, @Nullable String packageFilter) {
return filter(
getAllAssociations(userId),
// Null filter == get all associations
@@ -1444,25 +1225,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
return result;
}
- @NonNull
- private AndroidFuture<String> getDeviceProfilePermissionDescription(
- @Nullable String deviceProfile) {
- if (deviceProfile == null) {
- return AndroidFuture.completedFuture(null);
- }
-
- final AndroidFuture<String> result = new AndroidFuture<>();
- mPermissionControllerManager.getPrivilegesDescriptionStringForProfile(
- deviceProfile, FgThread.getExecutor(), desc -> {
- try {
- result.complete(String.valueOf(desc));
- } catch (Exception e) {
- result.completeExceptionally(e);
- }
- });
- return result;
- }
-
static int getFirstAssociationIdForUser(@UserIdInt int userId) {
// We want the IDs to start from 1, not 0.
return userId * ASSOCIATIONS_IDS_PER_USER_RANGE + 1;
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 92e0845012de..f57a852fe8c5 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -1075,17 +1075,22 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
if (shouldRecreateAudioPatch) {
mCommittedVolume = volume;
- if (mAudioPatch != null) {
- mAudioManager.releaseAudioPatch(mAudioPatch);
- }
- mAudioManager.createAudioPatch(
+ // only recreate if something was updated or audioPath is null
+ if (mAudioPatch == null || sinkUpdated ||sourceUpdated ) {
+ if (mAudioPatch != null) {
+ mAudioManager.releaseAudioPatch(mAudioPatch);
+ audioPatchArray[0] = null;
+ }
+ mAudioManager.createAudioPatch(
audioPatchArray,
new AudioPortConfig[] { sourceConfig },
sinkConfigs.toArray(new AudioPortConfig[sinkConfigs.size()]));
- mAudioPatch = audioPatchArray[0];
- if (sourceGainConfig != null) {
- mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig);
+ mAudioPatch = audioPatchArray[0];
}
+ }
+
+ if (sourceGainConfig != null) {
+ mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig);
}
}
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 fb5c557c8d4b..96af61737bff 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
@@ -100,7 +100,11 @@ public class FullScreenMagnificationControllerTest {
MagnificationAnimationCallback.class);
private final MagnificationInfoChangedCallback mRequestObserver = mock(
MagnificationInfoChangedCallback.class);
- final MessageCapturingHandler mMessageCapturingHandler = new MessageCapturingHandler(null);
+ private final MessageCapturingHandler mMessageCapturingHandler = new MessageCapturingHandler(
+ null);
+ private final MagnificationScaleProvider mScaleProvider = mock(
+ MagnificationScaleProvider.class);
+
ValueAnimator mMockValueAnimator;
ValueAnimator.AnimatorUpdateListener mTargetAnimationListener;
@@ -123,7 +127,7 @@ public class FullScreenMagnificationControllerTest {
initMockWindowManager();
mFullScreenMagnificationController = new FullScreenMagnificationController(
- mMockControllerCtx, new Object(), mRequestObserver);
+ mMockControllerCtx, new Object(), mRequestObserver, mScaleProvider);
}
@After
@@ -412,12 +416,12 @@ public class FullScreenMagnificationControllerTest {
MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter,
- FullScreenMagnificationController.MAX_SCALE);
+ MagnificationScaleProvider.MAX_SCALE);
MagnificationSpec endSpec = getMagnificationSpec(
- FullScreenMagnificationController.MAX_SCALE, offsets);
+ MagnificationScaleProvider.MAX_SCALE, offsets);
assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
- FullScreenMagnificationController.MAX_SCALE + 1.0f,
+ MagnificationScaleProvider.MAX_SCALE + 1.0f,
newCenter.x, newCenter.y, false, SERVICE_ID_1));
mMessageCapturingHandler.sendAllMessages();
@@ -632,31 +636,6 @@ public class FullScreenMagnificationControllerTest {
}
@Test
- public void testSetUserId_resetsOnlyIfIdChanges() {
- for (int i = 0; i < DISPLAY_COUNT; i++) {
- testSetUserId_resetsOnlyIfIdChanges(i);
- resetMockWindowManager();
- }
- }
-
- private void testSetUserId_resetsOnlyIfIdChanges(int displayId) {
- final int userId1 = 1;
- final int userId2 = 2;
-
- register(displayId);
- mFullScreenMagnificationController.setUserId(userId1);
- PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
- float scale = 2.0f;
- mFullScreenMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y,
- false, SERVICE_ID_1);
-
- mFullScreenMagnificationController.setUserId(userId1);
- assertTrue(mFullScreenMagnificationController.isMagnifying(displayId));
- mFullScreenMagnificationController.setUserId(userId2);
- assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
- }
-
- @Test
public void testResetIfNeeded_doesWhatItSays() {
for (int i = 0; i < DISPLAY_COUNT; i++) {
testResetIfNeeded_doesWhatItSays(i);
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 6c32f7e8bacb..2060223f6f98 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
@@ -22,6 +22,8 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static com.android.server.testutils.TestUtils.strictMock;
import static org.junit.Assert.assertFalse;
@@ -38,16 +40,15 @@ import static org.mockito.Mockito.when;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
-import android.content.Context;
import android.graphics.PointF;
import android.os.Handler;
import android.os.Message;
+import android.testing.TestableContext;
import android.util.DebugUtils;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
-import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.accessibility.AccessibilityManagerService;
@@ -60,6 +61,7 @@ import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -121,7 +123,6 @@ public class FullScreenMagnificationGestureHandlerTest {
private static final int DISPLAY_0 = 0;
- private Context mContext;
FullScreenMagnificationController mFullScreenMagnificationController;
@Mock
MagnificationGestureHandler.Callback mMockCallback;
@@ -134,6 +135,9 @@ public class FullScreenMagnificationGestureHandlerTest {
@Mock
AccessibilityTraceManager mMockTraceManager;
+ @Rule
+ public final TestableContext mContext = new TestableContext(getInstrumentation().getContext());
+
private OffsettableClock mClock;
private FullScreenMagnificationGestureHandler mMgh;
private TestHandler mHandler;
@@ -143,7 +147,6 @@ public class FullScreenMagnificationGestureHandlerTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getContext();
final FullScreenMagnificationController.ControllerContext mockController =
mock(FullScreenMagnificationController.ControllerContext.class);
final WindowManagerInternal mockWindowManager = mock(WindowManagerInternal.class);
@@ -157,14 +160,16 @@ public class FullScreenMagnificationGestureHandlerTest {
when(mockController.getAnimationDuration()).thenReturn(1000L);
when(mockWindowManager.setMagnificationCallbacks(eq(DISPLAY_0), any())).thenReturn(true);
mFullScreenMagnificationController = new FullScreenMagnificationController(mockController,
- new Object(), mMagnificationInfoChangedCallback) {
+ new Object(), mMagnificationInfoChangedCallback,
+ new MagnificationScaleProvider(mContext)) {
@Override
public boolean magnificationRegionContains(int displayId, float x, float y) {
return true;
}
@Override
- void setForceShowMagnifiableBounds(int displayId, boolean show) {}
+ void setForceShowMagnifiableBounds(int displayId, boolean show) {
+ }
};
mFullScreenMagnificationController.register(DISPLAY_0);
mClock = new OffsettableClock.Stopped();
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 2cb3d27229bc..69061c14c70e 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
@@ -46,6 +46,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
+import android.testing.DexmakerShareClassLoaderRule;
import android.view.Display;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.MagnificationAnimationCallback;
@@ -58,6 +59,7 @@ import com.android.server.accessibility.AccessibilityTraceManager;
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;
@@ -79,7 +81,8 @@ public class MagnificationControllerTest {
private static final float MAGNIFIED_CENTER_X = 100;
private static final float MAGNIFIED_CENTER_Y = 200;
private static final float DEFAULT_SCALE = 3f;
- private static final int CURRENT_USER_ID = UserHandle.USER_CURRENT;
+ private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM;
+ private static final int SECOND_USER_ID = CURRENT_USER_ID + 1;
private static final int MODE_WINDOW = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
private static final int MODE_FULLSCREEN =
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
@@ -94,6 +97,7 @@ public class MagnificationControllerTest {
private Context mContext;
@Mock
private FullScreenMagnificationController mScreenMagnificationController;
+ private MagnificationScaleProvider mScaleProvider;
@Captor
private ArgumentCaptor<MagnificationAnimationCallback> mCallbackArgumentCaptor;
@@ -103,6 +107,11 @@ public class MagnificationControllerTest {
private MagnificationController mMagnificationController;
private FullScreenMagnificationControllerStubber mScreenMagnificationControllerStubber;
+ // To mock package-private class
+ @Rule
+ public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
+ new DexmakerShareClassLoaderRule();
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -113,15 +122,17 @@ public class MagnificationControllerTest {
Settings.Secure.putFloatForUser(mMockResolver,
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, DEFAULT_SCALE,
CURRENT_USER_ID);
+ mScaleProvider = spy(new MagnificationScaleProvider(mContext));
mWindowMagnificationManager = Mockito.spy(
new WindowMagnificationManager(mContext, CURRENT_USER_ID,
- mock(WindowMagnificationManager.Callback.class), mTraceManager));
+ mock(WindowMagnificationManager.Callback.class), mTraceManager,
+ mScaleProvider));
mMockConnection = new MockWindowMagnificationConnection(true);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mScreenMagnificationControllerStubber = new FullScreenMagnificationControllerStubber(
mScreenMagnificationController);
mMagnificationController = spy(new MagnificationController(mService, new Object(), mContext,
- mScreenMagnificationController, mWindowMagnificationManager));
+ mScreenMagnificationController, mWindowMagnificationManager, mScaleProvider));
mMagnificationController.setMagnificationCapabilities(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
@@ -283,14 +294,16 @@ public class MagnificationControllerTest {
verify(mScreenMagnificationController).onDisplayRemoved(TEST_DISPLAY);
verify(mWindowMagnificationManager).onDisplayRemoved(TEST_DISPLAY);
+ verify(mScaleProvider).onDisplayRemoved(TEST_DISPLAY);
}
@Test
- public void updateUserIdIfNeeded_AllModulesAvailable_setUserId() {
- mMagnificationController.updateUserIdIfNeeded(CURRENT_USER_ID);
+ public void updateUserIdIfNeeded_AllModulesAvailable_disableMagnificationAndChangeUserId() {
+ mMagnificationController.updateUserIdIfNeeded(SECOND_USER_ID);
- verify(mScreenMagnificationController).setUserId(CURRENT_USER_ID);
- verify(mWindowMagnificationManager).setUserId(CURRENT_USER_ID);
+ verify(mScreenMagnificationController).resetAllIfNeeded(false);
+ verify(mWindowMagnificationManager).disableAllWindowMagnifiers();
+ verify(mScaleProvider).onUserChanged(SECOND_USER_ID);
}
@Test
@@ -575,6 +588,13 @@ public class MagnificationControllerTest {
verify(mMagnificationController, never()).logMagnificationModeWithIme(anyInt());
}
+ @Test
+ public void onUserRemoved_notifyScaleProvider() {
+ mMagnificationController.onUserRemoved(SECOND_USER_ID);
+
+ verify(mScaleProvider).onUserRemoved(SECOND_USER_ID);
+ }
+
private void setMagnificationEnabled(int mode) throws RemoteException {
setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
}
@@ -627,7 +647,8 @@ public class MagnificationControllerTest {
TEST_DISPLAY);
doAnswer(invocation -> mIsMagnifying).when(
mScreenMagnificationController).isForceShowMagnifiableBounds(TEST_DISPLAY);
- doAnswer(invocation -> mScale).when(mScreenMagnificationController).getPersistedScale();
+ doAnswer(invocation -> mScale).when(mScreenMagnificationController).getPersistedScale(
+ TEST_DISPLAY);
doAnswer(invocation -> mScale).when(mScreenMagnificationController).getScale(
TEST_DISPLAY);
doAnswer(invocation -> mCenterX).when(mScreenMagnificationController).getCenterX(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationScaleProviderTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationScaleProviderTest.java
new file mode 100644
index 000000000000..9b392b200821
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationScaleProviderTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility.magnification;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.UserHandle;
+import android.testing.TestableContext;
+import android.view.Display;
+
+import com.android.compatibility.common.util.TestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+/**
+ * Tests for {@link MagnificationScaleProvider}.
+ */
+public class MagnificationScaleProviderTest {
+
+ private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY + 1;
+ private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM;
+ private static final int SECOND_USER_ID = CURRENT_USER_ID + 1;
+
+ private static final float TEST_SCALE = 3;
+ private static final float DEFAULT_SCALE =
+ MagnificationScaleProvider.DEFAULT_MAGNIFICATION_SCALE;
+
+ @Rule
+ public final TestableContext mContext = new TestableContext(getInstrumentation().getContext());
+
+ private MagnificationScaleProvider mScaleProvider;
+
+ @Before
+ public void setUp() {
+ mScaleProvider = new MagnificationScaleProvider(mContext);
+ }
+
+ @Test
+ public void putScaleOnDefaultDisplay_getExpectedValue() throws Exception {
+ mScaleProvider.putScale(TEST_SCALE, Display.DEFAULT_DISPLAY);
+
+ TestUtils.waitUntil("settings value is not changed",
+ () -> Float.compare(mScaleProvider.getScale(Display.DEFAULT_DISPLAY),
+ TEST_SCALE) == 0);
+ }
+
+ @Test
+ public void putScaleOnTestDisplay_getExpectedValue() {
+ mScaleProvider.putScale(TEST_SCALE, TEST_DISPLAY);
+
+ assertEquals(TEST_SCALE, mScaleProvider.getScale(TEST_DISPLAY), 0);
+ }
+
+ @Test
+ public void onUserChanged_putScale_fallbackToDefaultScale() {
+ mScaleProvider.putScale(TEST_SCALE, TEST_DISPLAY);
+
+ mScaleProvider.onUserChanged(SECOND_USER_ID);
+ assertEquals(DEFAULT_SCALE, mScaleProvider.getScale(TEST_DISPLAY), 0);
+ }
+
+ @Test
+ public void onUserRemoved_setScaleOnSecondUser_fallbackToDefaultScale() {
+ mScaleProvider.onUserChanged(SECOND_USER_ID);
+ mScaleProvider.putScale(TEST_SCALE, TEST_DISPLAY);
+ mScaleProvider.onUserChanged(CURRENT_USER_ID);
+
+ mScaleProvider.onUserRemoved(SECOND_USER_ID);
+ // Assume the second user is created with the same id
+ mScaleProvider.onUserChanged(SECOND_USER_ID);
+
+ assertEquals(DEFAULT_SCALE, mScaleProvider.getScale(TEST_DISPLAY), 0);
+ }
+
+ @Test
+ public void onTestDisplayRemoved_setScaleOnTestDisplay_fallbackToDefaultScale() {
+ mScaleProvider.putScale(TEST_SCALE, TEST_DISPLAY);
+
+ mScaleProvider.onDisplayRemoved(TEST_DISPLAY);
+
+ assertEquals(DEFAULT_SCALE, mScaleProvider.getScale(TEST_DISPLAY), 0);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index 95f43275376e..1b8aff50d2e2 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -21,10 +21,10 @@ import static com.android.server.testutils.TestUtils.strictMock;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
-import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.RemoteException;
+import android.testing.TestableContext;
import android.util.DebugUtils;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -39,6 +39,7 @@ import com.android.server.accessibility.utils.TouchEventGenerator;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -67,7 +68,10 @@ public class WindowMagnificationGestureHandlerTest {
public static final float DEFAULT_TAP_Y = 299;
private static final int DISPLAY_0 = MockWindowMagnificationConnection.TEST_DISPLAY;
- private Context mContext;
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getContext());
+
private WindowMagnificationManager mWindowMagnificationManager;
private MockWindowMagnificationConnection mMockConnection;
private WindowMagnificationGestureHandler mWindowMagnificationGestureHandler;
@@ -79,9 +83,9 @@ public class WindowMagnificationGestureHandlerTest {
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getInstrumentation().getContext();
mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0,
- mock(WindowMagnificationManager.Callback.class), mMockTrace);
+ mock(WindowMagnificationManager.Callback.class), mMockTrace,
+ new MagnificationScaleProvider(mContext));
mMockConnection = new MockWindowMagnificationConnection();
mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler(
mContext, mWindowMagnificationManager, mMockTrace, mMockCallback,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index af6d40f2fdf2..da881c4e6494 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -67,7 +67,7 @@ import org.mockito.invocation.InvocationOnMock;
public class WindowMagnificationManagerTest {
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
- private static final int CURRENT_USER_ID = UserHandle.USER_CURRENT;
+ private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM;
private MockWindowMagnificationConnection mMockConnection;
@Mock
@@ -91,7 +91,7 @@ public class WindowMagnificationManagerTest {
mResolver = new MockContentResolver();
mMockConnection = new MockWindowMagnificationConnection();
mWindowMagnificationManager = new WindowMagnificationManager(mContext, CURRENT_USER_ID,
- mMockCallback, mMockTrace);
+ mMockCallback, mMockTrace, new MagnificationScaleProvider(mContext));
when(mContext.getContentResolver()).thenReturn(mResolver);
doAnswer((InvocationOnMock invocation) -> {
@@ -230,7 +230,7 @@ public class WindowMagnificationManagerTest {
public void getPersistedScale() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- assertEquals(mWindowMagnificationManager.getPersistedScale(), 2.5f);
+ assertEquals(mWindowMagnificationManager.getPersistedScale(TEST_DISPLAY), 2.5f);
}
@Test
@@ -264,7 +264,7 @@ public class WindowMagnificationManagerTest {
mWindowMagnificationManager.setScale(TEST_DISPLAY, 10.0f);
assertEquals(mWindowMagnificationManager.getScale(TEST_DISPLAY),
- WindowMagnificationManager.MAX_SCALE);
+ MagnificationScaleProvider.MAX_SCALE);
}
@Test