From 4ce1ddff798612b5a1e38297b2c5222516f100f8 Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 25 Oct 2019 13:46:47 -0700 Subject: [PATCH] Added WindowMagnification for Accessibility in System UI Added support for window magnification as an accessibility feature. The UI can either be dragged to a new a location or arrow controls can move the window around. Test: adb shell settings put secure window_magnification 1 Bug: 136250281 Change-Id: If3098df098f2a1b88b2170e773dccc8f86946abf --- core/java/android/provider/Settings.java | 6 + .../android/provider/SettingsBackupTest.java | 3 +- .../ic_control_magnification_grey.xml | 22 + .../res/layout/magnifier_controllers.xml | 65 +++ .../res/layout/window_magnifier_view.xml | 71 +++ packages/SystemUI/res/values/colors.xml | 1 + packages/SystemUI/res/values/config.xml | 1 + packages/SystemUI/res/values/dimens.xml | 12 + packages/SystemUI/res/values/integers.xml | 2 + packages/SystemUI/res/values/strings.xml | 8 + .../shared/system/WindowManagerWrapper.java | 20 + .../accessibility/WindowMagnification.java | 83 ++++ .../WindowMagnificationController.java | 424 ++++++++++++++++++ .../systemui/dagger/SystemUIBinder.java | 7 + 14 files changed, 724 insertions(+), 1 deletion(-) create mode 100644 packages/SystemUI/res/drawable/ic_control_magnification_grey.xml create mode 100644 packages/SystemUI/res/layout/magnifier_controllers.xml create mode 100644 packages/SystemUI/res/layout/window_magnifier_view.xml create mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java create mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 197d814e59d53..6c83a763ad2eb 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8415,6 +8415,12 @@ public final class Settings { */ public static final String PEOPLE_STRIP = "people_strip"; + /** + * Controls if window magnification is enabled. + * @hide + */ + public static final String WINDOW_MAGNIFICATION = "window_magnification"; + /** * Keys we no longer back up under the current schema, but want to continue to * process when restoring historical backup datasets. diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 4a10e85206d3d..5d0db01cd5ae8 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -734,7 +734,8 @@ public class SettingsBackupTest { Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, Settings.Secure.FACE_UNLOCK_RE_ENROLL, - Settings.Secure.TAP_GESTURE); + Settings.Secure.TAP_GESTURE, + Settings.Secure.WINDOW_MAGNIFICATION); @Test public void systemSettingsBackedUpOrBlacklisted() { diff --git a/packages/SystemUI/res/drawable/ic_control_magnification_grey.xml b/packages/SystemUI/res/drawable/ic_control_magnification_grey.xml new file mode 100644 index 0000000000000..80ce8c1100416 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_control_magnification_grey.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/packages/SystemUI/res/layout/magnifier_controllers.xml b/packages/SystemUI/res/layout/magnifier_controllers.xml new file mode 100644 index 0000000000000..0203cd4f506be --- /dev/null +++ b/packages/SystemUI/res/layout/magnifier_controllers.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/layout/window_magnifier_view.xml b/packages/SystemUI/res/layout/window_magnifier_view.xml new file mode 100644 index 0000000000000..f8186129f1113 --- /dev/null +++ b/packages/SystemUI/res/layout/window_magnifier_view.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 92c74770a3c4b..c1424657cf4f4 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -211,4 +211,5 @@ #FF34A853 #FF4285F4 + #FF9900 diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index e896c162af7d6..640f31bc9fe8a 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -295,6 +295,7 @@ com.android.systemui.SizeCompatModeActivityController com.android.systemui.statusbar.notification.InstantAppNotifier com.android.systemui.theme.ThemeOverlayController + com.android.systemui.accessibility.WindowMagnification diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index c9481164c2026..da0323ac73579 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1139,4 +1139,16 @@ 350dp 8dp 10dp + + 5dp + 5dp + 25dp + 100dp + 35dp + 90dp + 35dp + 45dp + 45dp + 40dp + diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml index deae7e2c181c5..c1cf7b4200789 100644 --- a/packages/SystemUI/res/values/integers.xml +++ b/packages/SystemUI/res/values/integers.xml @@ -32,4 +32,6 @@ 2 + 2 + \ No newline at end of file diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 1053750a55385..bc808b3cc5315 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2492,4 +2492,12 @@ Standby + + + + Magnification Overlay Window + + Magnification Window + + Magnification Window Controls diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index 22d1675cf17e7..9f13718ec2369 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -27,6 +27,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; import android.util.Log; +import android.view.SurfaceControl; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -215,4 +216,23 @@ public class WindowManagerWrapper { public void removePinnedStackListener(PinnedStackListener listener) { mPinnedStackListenerForwarder.removeListener(listener); } + + /** + * Mirrors a specified display. The SurfaceControl returned is the root of the mirrored + * hierarchy. + * + * @param displayId The id of the display to mirror + * @return The SurfaceControl for the root of the mirrored hierarchy. + */ + public SurfaceControl mirrorDisplay(final int displayId) { + try { + SurfaceControl outSurfaceControl = new SurfaceControl(); + WindowManagerGlobal.getWindowManagerService().mirrorDisplay(displayId, + outSurfaceControl); + return outSurfaceControl; + } catch (RemoteException e) { + Log.e(TAG, "Unable to reach window manager", e); + } + return null; + } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java new file mode 100644 index 0000000000000..6178ff2ab2cb7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings; + +import com.android.systemui.SystemUI; +import com.android.systemui.dagger.qualifiers.MainHandler; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Class to handle changes to setting window_magnification value. + */ +@Singleton +public class WindowMagnification extends SystemUI { + private WindowMagnificationController mWindowMagnificationController; + private final Handler mHandler; + + @Inject + public WindowMagnification(Context context, @MainHandler Handler mainHandler) { + super(context); + mHandler = mainHandler; + } + + @Override + public void start() { + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.WINDOW_MAGNIFICATION), + true, new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + updateWindowMagnification(); + } + }); + } + + private void updateWindowMagnification() { + try { + boolean enable = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.WINDOW_MAGNIFICATION) != 0; + if (enable) { + enableMagnification(); + } else { + disableMagnification(); + } + } catch (Settings.SettingNotFoundException e) { + disableMagnification(); + } + } + + private void enableMagnification() { + if (mWindowMagnificationController == null) { + mWindowMagnificationController = new WindowMagnificationController(mContext, mHandler); + } + mWindowMagnificationController.createWindowMagnification(); + } + + private void disableMagnification() { + if (mWindowMagnificationController != null) { + mWindowMagnificationController.deleteWindowMagnification(); + } + mWindowMagnificationController = null; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java new file mode 100644 index 0000000000000..e3694ac532fe4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.graphics.PointF; +import android.graphics.Rect; +import android.os.Binder; +import android.os.Handler; +import android.view.Display; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.Surface; +import android.view.SurfaceControl; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowManager; + +import com.android.systemui.R; +import com.android.systemui.shared.system.WindowManagerWrapper; + +/** + * Class to handle adding and removing a window magnification. + */ +public class WindowMagnificationController implements View.OnClickListener, + View.OnLongClickListener, View.OnTouchListener, SurfaceHolder.Callback { + private final int mBorderSize; + private final int mMoveFrameAmountShort; + private final int mMoveFrameAmountLong; + + private final Context mContext; + private final Point mDisplaySize = new Point(); + private final int mDisplayId; + private final Handler mHandler; + private final Rect mMagnificationFrame = new Rect(); + private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); + + private final WindowManager mWm; + + private float mScale; + + private final Rect mTmpRect = new Rect(); + + // The root of the mirrored content + private SurfaceControl mMirrorSurface; + + private boolean mIsPressedDown; + + private View mLeftControl; + private View mUpControl; + private View mRightControl; + private View mBottomControl; + + private View mDragView; + private View mLeftDrag; + private View mTopDrag; + private View mRightDrag; + private View mBottomDrag; + + private final PointF mLastDrag = new PointF(); + private final Point mMoveWindowOffset = new Point(); + + private View mMirrorView; + private SurfaceView mMirrorSurfaceView; + private View mControlsView; + private View mOverlayView; + + private MoveMirrorRunnable mMoveMirrorRunnable = new MoveMirrorRunnable(); + + WindowMagnificationController(Context context, Handler handler) { + mContext = context; + mHandler = handler; + Display display = mContext.getDisplay(); + display.getSize(mDisplaySize); + mDisplayId = mContext.getDisplayId(); + + mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + + Resources r = context.getResources(); + mBorderSize = (int) r.getDimension(R.dimen.magnification_border_size); + mMoveFrameAmountShort = (int) r.getDimension(R.dimen.magnification_frame_move_short); + mMoveFrameAmountLong = (int) r.getDimension(R.dimen.magnification_frame_move_long); + + mScale = r.getInteger(R.integer.magnification_default_scale); + } + + /** + * Creates a magnification window if it doesn't already exist. + */ + void createWindowMagnification() { + if (mMirrorView != null) { + return; + } + createOverlayWindow(); + } + + private void createOverlayWindow() { + WindowManager.LayoutParams params = new WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSPARENT); + params.gravity = Gravity.TOP | Gravity.LEFT; + params.token = new Binder(); + params.setTitle(mContext.getString(R.string.magnification_overlay_title)); + + mOverlayView = new View(mContext); + mOverlayView.getViewTreeObserver().addOnWindowAttachListener( + new ViewTreeObserver.OnWindowAttachListener() { + @Override + public void onWindowAttached() { + mOverlayView.getViewTreeObserver().removeOnWindowAttachListener(this); + createMirrorWindow(); + createControls(); + } + + @Override + public void onWindowDetached() { + + } + }); + + mOverlayView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + + mWm.addView(mOverlayView, params); + } + + /** + * Deletes the magnification window. + */ + void deleteWindowMagnification() { + if (mMirrorSurface != null) { + mTransaction.remove(mMirrorSurface).apply(); + mMirrorSurface = null; + } + + if (mOverlayView != null) { + mWm.removeView(mOverlayView); + mOverlayView = null; + } + + if (mMirrorView != null) { + mWm.removeView(mMirrorView); + mMirrorView = null; + } + + if (mControlsView != null) { + mWm.removeView(mControlsView); + mControlsView = null; + } + } + + private void createMirrorWindow() { + setInitialStartBounds(); + + // The window should be the size the mirrored surface will be but also add room for the + // border and the drag handle. + int dragViewHeight = (int) mContext.getResources().getDimension( + R.dimen.magnification_drag_view_height); + int windowWidth = mMagnificationFrame.width() + 2 * mBorderSize; + int windowHeight = mMagnificationFrame.height() + dragViewHeight + 2 * mBorderSize; + + WindowManager.LayoutParams params = new WindowManager.LayoutParams( + windowWidth, windowHeight, + WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSPARENT); + params.gravity = Gravity.TOP | Gravity.LEFT; + params.token = mOverlayView.getWindowToken(); + params.x = mMagnificationFrame.left; + params.y = mMagnificationFrame.top; + params.setTitle(mContext.getString(R.string.magnification_window_title)); + + mMirrorView = LayoutInflater.from(mContext).inflate(R.layout.window_magnifier_view, null); + mMirrorSurfaceView = mMirrorView.findViewById(R.id.surface_view); + // This places the SurfaceView's SurfaceControl above the ViewRootImpl's SurfaceControl to + // ensure the mirrored area can get touch instead of going to the window + mMirrorSurfaceView.setZOrderOnTop(true); + + mMirrorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + mWm.addView(mMirrorView, params); + + SurfaceHolder holder = mMirrorSurfaceView.getHolder(); + holder.addCallback(this); + holder.setFormat(PixelFormat.RGBA_8888); + + addDragTouchListeners(); + } + + private void createControls() { + int controlsSize = (int) mContext.getResources().getDimension( + R.dimen.magnification_controls_size); + + WindowManager.LayoutParams lp = new WindowManager.LayoutParams(controlsSize, controlsSize, + WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL, + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.RGBA_8888); + lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; + lp.token = mOverlayView.getWindowToken(); + lp.setTitle(mContext.getString(R.string.magnification_controls_title)); + + mControlsView = LayoutInflater.from(mContext).inflate(R.layout.magnifier_controllers, null); + mWm.addView(mControlsView, lp); + + mLeftControl = mControlsView.findViewById(R.id.left_control); + mUpControl = mControlsView.findViewById(R.id.up_control); + mRightControl = mControlsView.findViewById(R.id.right_control); + mBottomControl = mControlsView.findViewById(R.id.down_control); + + mLeftControl.setOnClickListener(this); + mUpControl.setOnClickListener(this); + mRightControl.setOnClickListener(this); + mBottomControl.setOnClickListener(this); + + mLeftControl.setOnLongClickListener(this); + mUpControl.setOnLongClickListener(this); + mRightControl.setOnLongClickListener(this); + mBottomControl.setOnLongClickListener(this); + + mLeftControl.setOnTouchListener(this); + mUpControl.setOnTouchListener(this); + mRightControl.setOnTouchListener(this); + mBottomControl.setOnTouchListener(this); + } + + private void setInitialStartBounds() { + // Sets the initial frame area for the mirror and places it in the center of the display. + int initSize = Math.min(mDisplaySize.x, mDisplaySize.y) / 2; + int initX = mDisplaySize.x / 2 - initSize / 2; + int initY = mDisplaySize.y / 2 - initSize / 2; + mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize); + } + + /** + * This is called once the surfaceView is created so the mirrored content can be placed as a + * child of the surfaceView. + */ + private void createMirror() { + mMirrorSurface = WindowManagerWrapper.getInstance().mirrorDisplay(mDisplayId); + if (!mMirrorSurface.isValid()) { + return; + } + mTransaction.show(mMirrorSurface) + .reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl()); + + modifyWindowMagnification(mTransaction); + mTransaction.apply(); + } + + private void addDragTouchListeners() { + mDragView = mMirrorView.findViewById(R.id.drag_handle); + mLeftDrag = mMirrorView.findViewById(R.id.left_handle); + mTopDrag = mMirrorView.findViewById(R.id.top_handle); + mRightDrag = mMirrorView.findViewById(R.id.right_handle); + mBottomDrag = mMirrorView.findViewById(R.id.bottom_handle); + + mDragView.setOnTouchListener(this); + mLeftDrag.setOnTouchListener(this); + mTopDrag.setOnTouchListener(this); + mRightDrag.setOnTouchListener(this); + mBottomDrag.setOnTouchListener(this); + } + + /** + * Modifies the placement of the mirrored content. + */ + private void modifyWindowMagnification(SurfaceControl.Transaction t) { + Rect sourceBounds = getSourceBounds(mMagnificationFrame, mScale); + // The final destination for the magnification surface should be at 0,0 since the + // ViewRootImpl's position will change + mTmpRect.set(0, 0, mMagnificationFrame.width(), mMagnificationFrame.height()); + + WindowManager.LayoutParams params = + (WindowManager.LayoutParams) mMirrorView.getLayoutParams(); + params.x = mMagnificationFrame.left; + params.y = mMagnificationFrame.top; + mWm.updateViewLayout(mMirrorView, params); + + t.setGeometry(mMirrorSurface, sourceBounds, mTmpRect, Surface.ROTATION_0); + } + + @Override + public void onClick(View v) { + setMoveOffset(v, mMoveFrameAmountShort); + moveMirrorFromControls(); + } + + @Override + public boolean onLongClick(View v) { + mIsPressedDown = true; + setMoveOffset(v, mMoveFrameAmountLong); + mHandler.post(mMoveMirrorRunnable); + return true; + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + if (v == mLeftControl || v == mUpControl || v == mRightControl || v == mBottomControl) { + return handleControlTouchEvent(event); + } else if (v == mDragView || v == mLeftDrag || v == mTopDrag || v == mRightDrag + || v == mBottomDrag) { + return handleDragTouchEvent(event); + } + return false; + } + + private boolean handleControlTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mIsPressedDown = false; + break; + } + return false; + } + + private boolean handleDragTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mLastDrag.set(event.getRawX(), event.getRawY()); + return true; + case MotionEvent.ACTION_MOVE: + int xDiff = (int) (event.getRawX() - mLastDrag.x); + int yDiff = (int) (event.getRawY() - mLastDrag.y); + mMagnificationFrame.offset(xDiff, yDiff); + mLastDrag.set(event.getRawX(), event.getRawY()); + modifyWindowMagnification(mTransaction); + mTransaction.apply(); + return true; + } + return false; + } + + private void setMoveOffset(View v, int moveFrameAmount) { + mMoveWindowOffset.set(0, 0); + + if (v == mLeftControl) { + mMoveWindowOffset.x = -moveFrameAmount; + } else if (v == mUpControl) { + mMoveWindowOffset.y = -moveFrameAmount; + } else if (v == mRightControl) { + mMoveWindowOffset.x = moveFrameAmount; + } else if (v == mBottomControl) { + mMoveWindowOffset.y = moveFrameAmount; + } + } + + private void moveMirrorFromControls() { + mMagnificationFrame.offset(mMoveWindowOffset.x, mMoveWindowOffset.y); + + modifyWindowMagnification(mTransaction); + mTransaction.apply(); + } + + /** + * Calculates the desired source bounds. This will be the area under from the center of the + * displayFrame, factoring in scale. + */ + private Rect getSourceBounds(Rect displayFrame, float scale) { + int halfWidth = displayFrame.width() / 2; + int halfHeight = displayFrame.height() / 2; + int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale)); + int right = displayFrame.right - (halfWidth - (int) (halfWidth / scale)); + int top = displayFrame.top + (halfHeight - (int) (halfHeight / scale)); + int bottom = displayFrame.bottom - (halfHeight - (int) (halfHeight / scale)); + return new Rect(left, top, right, bottom); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + createMirror(); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + } + + class MoveMirrorRunnable implements Runnable { + @Override + public void run() { + if (mIsPressedDown) { + moveMirrorFromControls(); + mHandler.postDelayed(mMoveMirrorRunnable, 100); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index 3cf14d65e5b85..99dd5e2356d66 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -21,6 +21,7 @@ import com.android.systemui.ScreenDecorations; import com.android.systemui.SizeCompatModeActivityController; import com.android.systemui.SliceBroadcastRelayHandler; import com.android.systemui.SystemUI; +import com.android.systemui.accessibility.WindowMagnification; import com.android.systemui.biometrics.AuthController; import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -156,4 +157,10 @@ public abstract class SystemUIBinder { @IntoMap @ClassKey(VolumeUI.class) public abstract SystemUI bindVolumeUI(VolumeUI sysui); + + /** Inject into WindowMagnification. */ + @Binds + @IntoMap + @ClassKey(WindowMagnification.class) + public abstract SystemUI bindWindowMagnification(WindowMagnification sysui); }