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
This commit is contained in:
chaviw
2019-10-25 13:46:47 -07:00
parent df15522021
commit 4ce1ddff79
14 changed files with 724 additions and 1 deletions

View File

@@ -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.

View File

@@ -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() {

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<vector android:height="96dp" android:viewportHeight="24"
android:viewportWidth="24" android:width="96dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#757575" android:pathData="M15.54,5.54L13.77,7.3 12,5.54 10.23,7.3 8.46,5.54 12,2zM18.46,15.54l-1.76,-1.77L18.46,12l-1.76,-1.77 1.76,-1.77L22,12zM8.46,18.46l1.77,-1.76L12,18.46l1.77,-1.76 1.77,1.76L12,22zM5.54,8.46l1.76,1.77L5.54,12l1.76,1.77 -1.76,1.77L2,12z"/>
<path android:fillColor="#757575" android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
</vector>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/magnification_controls_size"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_height="@dimen/magnification_controls_size"
android:gravity="center">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:focusable="true"
android:id="@+id/controller"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_control_magnification_grey" />
<View
android:id="@+id/left_control"
android:layout_width="@dimen/magnifier_left_right_controls_width"
android:layout_height="@dimen/magnifier_left_right_controls_height"
android:layout_alignLeft="@+id/controller"
android:layout_centerVertical="true" />
<View
android:id="@+id/up_control"
android:layout_width="@dimen/magnifier_up_down_controls_width"
android:layout_height="@dimen/magnifier_up_down_controls_height"
android:layout_alignTop="@+id/controller"
android:layout_centerHorizontal="true" />
<View
android:id="@+id/right_control"
android:layout_width="@dimen/magnifier_left_right_controls_width"
android:layout_height="@dimen/magnifier_left_right_controls_height"
android:layout_alignRight="@+id/controller"
android:layout_centerVertical="true" />
<View
android:id="@+id/down_control"
android:layout_width="@dimen/magnifier_up_down_controls_width"
android:layout_height="@dimen/magnifier_up_down_controls_height"
android:layout_alignBottom="@+id/controller"
android:layout_centerHorizontal="true" />
</RelativeLayout>
</FrameLayout>

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<SurfaceView
android:layout_marginStart="@dimen/magnification_border_size"
android:layout_marginTop="@dimen/magnification_border_size"
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:id="@+id/left_handle"
android:layout_width="@dimen/magnification_border_size"
android:layout_height="match_parent"
android:layout_above="@+id/drag_handle"
android:background="@color/magnification_border_color" />
<View
android:id="@+id/top_handle"
android:layout_width="match_parent"
android:layout_height="@dimen/magnification_border_size"
android:background="@color/magnification_border_color" />
<View
android:id="@+id/right_handle"
android:layout_width="@dimen/magnification_border_size"
android:layout_height="match_parent"
android:layout_above="@+id/drag_handle"
android:layout_alignParentEnd="true"
android:background="@color/magnification_border_color" />
<View
android:id="@+id/bottom_handle"
android:layout_width="match_parent"
android:layout_height="@dimen/magnification_border_size"
android:layout_above="@+id/drag_handle"
android:background="@color/magnification_border_color" />
<View
android:id="@+id/drag_handle"
android:layout_width="@dimen/magnification_drag_view_width"
android:layout_height="@dimen/magnification_drag_view_height"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@color/magnification_border_color" />
</RelativeLayout>
</FrameLayout>

View File

@@ -211,4 +211,5 @@
<color name="GM2_green_500">#FF34A853</color>
<color name="GM2_blue_500">#FF4285F4</color>
<color name="magnification_border_color">#FF9900</color>
</resources>

View File

@@ -295,6 +295,7 @@
<item>com.android.systemui.SizeCompatModeActivityController</item>
<item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
<item>com.android.systemui.theme.ThemeOverlayController</item>
<item>com.android.systemui.accessibility.WindowMagnification</item>
</string-array>
<!-- SystemUI vender service, used in config_systemUIServiceComponents. -->

View File

@@ -1139,4 +1139,16 @@
<dimen name="qs_media_width">350dp</dimen>
<dimen name="qs_media_padding">8dp</dimen>
<dimen name="qs_media_corner_radius">10dp</dimen>
<dimen name="magnification_border_size">5dp</dimen>
<dimen name="magnification_frame_move_short">5dp</dimen>
<dimen name="magnification_frame_move_long">25dp</dimen>
<dimen name="magnification_drag_view_width">100dp</dimen>
<dimen name="magnification_drag_view_height">35dp</dimen>
<dimen name="magnification_controls_size">90dp</dimen>
<dimen name="magnifier_left_right_controls_width">35dp</dimen>
<dimen name="magnifier_left_right_controls_height">45dp</dimen>
<dimen name="magnifier_up_down_controls_width">45dp</dimen>
<dimen name="magnifier_up_down_controls_height">40dp</dimen>
</resources>

View File

@@ -32,4 +32,6 @@
<!-- Ratio of "right" end of status bar that will swipe to QS. -->
<integer name="qs_split_fraction">2</integer>
<integer name="magnification_default_scale">2</integer>
</resources>

View File

@@ -2492,4 +2492,12 @@
<!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] -->
<string name="inattentive_sleep_warning_title">Standby</string>
<!-- Window Magnification strings -->
<!-- Title for Magnification Overlay Window [CHAR LIMIT=NONE] -->
<string name="magnification_overlay_title">Magnification Overlay Window</string>
<!-- Title for Magnification Window [CHAR LIMIT=NONE] -->
<string name="magnification_window_title">Magnification Window</string>
<!-- Title for Magnification Controls Window [CHAR LIMIT=NONE] -->
<string name="magnification_controls_title">Magnification Window Controls</string>
</resources>

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}