1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.accessibility.magnification; 18 19 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION; 20 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK; 21 import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK; 22 23 import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID; 24 import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID; 25 26 import android.annotation.IntDef; 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.content.BroadcastReceiver; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.graphics.PointF; 34 import android.graphics.Rect; 35 import android.graphics.Region; 36 import android.os.Binder; 37 import android.os.IBinder; 38 import android.os.RemoteException; 39 import android.os.SystemClock; 40 import android.util.Slog; 41 import android.util.SparseArray; 42 import android.util.SparseBooleanArray; 43 import android.view.MotionEvent; 44 import android.view.accessibility.IWindowMagnificationConnection; 45 import android.view.accessibility.IWindowMagnificationConnectionCallback; 46 import android.view.accessibility.MagnificationAnimationCallback; 47 48 import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; 49 import com.android.internal.annotations.GuardedBy; 50 import com.android.internal.annotations.VisibleForTesting; 51 import com.android.server.LocalServices; 52 import com.android.server.accessibility.AccessibilityTraceManager; 53 import com.android.server.statusbar.StatusBarManagerInternal; 54 import com.android.server.wm.WindowManagerInternal; 55 56 import java.lang.annotation.Retention; 57 import java.lang.annotation.RetentionPolicy; 58 import java.util.concurrent.atomic.AtomicLongFieldUpdater; 59 60 /** 61 * A class to manipulate window magnification through {@link WindowMagnificationConnectionWrapper} 62 * create by {@link #setConnection(IWindowMagnificationConnection)}. To set the connection with 63 * SysUI, call {@code StatusBarManagerInternal#requestWindowMagnificationConnection(boolean)}. 64 * The applied magnification scale is constrained by 65 * {@link MagnificationScaleProvider#constrainScale(float)} 66 */ 67 public class WindowMagnificationManager implements 68 PanningScalingHandler.MagnificationDelegate, 69 WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks { 70 71 private static final boolean DBG = false; 72 73 private static final String TAG = "WindowMagnificationMgr"; 74 75 /** 76 * Indicate that the magnification window is at the magnification center. 77 */ 78 public static final int WINDOW_POSITION_AT_CENTER = 0; 79 80 /** 81 * Indicate that the magnification window is at the top-left side of the magnification 82 * center. The offset is equal to a half of MirrorSurfaceView. So, the bottom-right corner 83 * of the window is at the magnification center. 84 */ 85 public static final int WINDOW_POSITION_AT_TOP_LEFT = 1; 86 87 @Retention(RetentionPolicy.SOURCE) 88 @IntDef(prefix = { "WINDOW_POSITION_AT_" }, value = { 89 WINDOW_POSITION_AT_CENTER, 90 WINDOW_POSITION_AT_TOP_LEFT 91 }) 92 public @interface WindowPosition {} 93 94 /** Window magnification connection is connecting. */ 95 private static final int CONNECTING = 0; 96 /** Window magnification connection is connected. */ 97 private static final int CONNECTED = 1; 98 /** Window magnification connection is disconnecting. */ 99 private static final int DISCONNECTING = 2; 100 /** Window magnification connection is disconnected. */ 101 private static final int DISCONNECTED = 3; 102 103 @Retention(RetentionPolicy.SOURCE) 104 @IntDef(prefix = {"CONNECTION_STATE"}, value = { 105 CONNECTING, 106 CONNECTED, 107 DISCONNECTING, 108 DISCONNECTED 109 }) 110 private @interface ConnectionState { 111 } 112 connectionStateToString(@onnectionState int state)113 private static String connectionStateToString(@ConnectionState int state) { 114 switch (state) { 115 case CONNECTING: return "CONNECTING"; 116 case CONNECTED: return "CONNECTED"; 117 case DISCONNECTING: return "DISCONNECTING"; 118 case DISCONNECTED: return "DISCONNECTED"; 119 default: 120 return "UNKNOWN:" + state; 121 } 122 } 123 124 @ConnectionState 125 private int mConnectionState = DISCONNECTED; 126 127 private static final int WAIT_CONNECTION_TIMEOUT_MILLIS = 100; 128 129 private final Object mLock; 130 private final Context mContext; 131 @VisibleForTesting 132 @GuardedBy("mLock") 133 @Nullable 134 WindowMagnificationConnectionWrapper mConnectionWrapper; 135 @GuardedBy("mLock") 136 private ConnectionCallback mConnectionCallback; 137 @GuardedBy("mLock") 138 private SparseArray<WindowMagnifier> mWindowMagnifiers = new SparseArray<>(); 139 // Whether the following typing focus feature for magnification is enabled. 140 private boolean mMagnificationFollowTypingEnabled = true; 141 @GuardedBy("mLock") 142 private final SparseBooleanArray mIsImeVisibleArray = new SparseBooleanArray(); 143 144 private boolean mReceiverRegistered = false; 145 @VisibleForTesting 146 protected final BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() { 147 @Override 148 public void onReceive(Context context, Intent intent) { 149 final int displayId = context.getDisplayId(); 150 removeMagnificationButton(displayId); 151 disableWindowMagnification(displayId, false, null); 152 } 153 }; 154 155 /** 156 * Callback to handle magnification actions from system UI. 157 */ 158 public interface Callback { 159 160 /** 161 * Called when the accessibility action of scale requests to be performed. 162 * It is invoked from System UI. And the action is provided by the mirror window. 163 * 164 * @param displayId The logical display id. 165 * @param scale the target scale, or {@link Float#NaN} to leave unchanged 166 */ onPerformScaleAction(int displayId, float scale)167 void onPerformScaleAction(int displayId, float scale); 168 169 /** 170 * Called when the accessibility action is performed. 171 * 172 * @param displayId The logical display id. 173 */ onAccessibilityActionPerformed(int displayId)174 void onAccessibilityActionPerformed(int displayId); 175 176 /** 177 * Called when the state of the magnification activation is changed. 178 * 179 * @param displayId The logical display id. 180 * @param activated {@code true} if the magnification is activated, otherwise {@code false}. 181 */ onWindowMagnificationActivationState(int displayId, boolean activated)182 void onWindowMagnificationActivationState(int displayId, boolean activated); 183 184 /** 185 * Called when the magnification source bounds are changed. 186 * 187 * @param displayId The logical display id. 188 * @param bounds The magnified source bounds on the display. 189 */ onSourceBoundsChanged(int displayId, Rect bounds)190 void onSourceBoundsChanged(int displayId, Rect bounds); 191 192 /** 193 * Called from {@link IWindowMagnificationConnection} to request changing the magnification 194 * mode on the given display. 195 * 196 * @param displayId the logical display id 197 * @param magnificationMode the target magnification mode 198 */ onChangeMagnificationMode(int displayId, int magnificationMode)199 void onChangeMagnificationMode(int displayId, int magnificationMode); 200 } 201 202 private final Callback mCallback; 203 private final AccessibilityTraceManager mTrace; 204 private final MagnificationScaleProvider mScaleProvider; 205 WindowMagnificationManager(Context context, Object lock, @NonNull Callback callback, AccessibilityTraceManager trace, MagnificationScaleProvider scaleProvider)206 public WindowMagnificationManager(Context context, Object lock, @NonNull Callback callback, 207 AccessibilityTraceManager trace, MagnificationScaleProvider scaleProvider) { 208 mContext = context; 209 mLock = lock; 210 mCallback = callback; 211 mTrace = trace; 212 mScaleProvider = scaleProvider; 213 } 214 215 /** 216 * Sets {@link IWindowMagnificationConnection}. 217 * 218 * @param connection {@link IWindowMagnificationConnection} 219 */ setConnection(@ullable IWindowMagnificationConnection connection)220 public void setConnection(@Nullable IWindowMagnificationConnection connection) { 221 if (DBG) { 222 Slog.d(TAG, "setConnection :" + connection + ", mConnectionState=" 223 + connectionStateToString(mConnectionState)); 224 } 225 synchronized (mLock) { 226 // Reset connectionWrapper. 227 if (mConnectionWrapper != null) { 228 mConnectionWrapper.setConnectionCallback(null); 229 if (mConnectionCallback != null) { 230 mConnectionCallback.mExpiredDeathRecipient = true; 231 } 232 mConnectionWrapper.unlinkToDeath(mConnectionCallback); 233 mConnectionWrapper = null; 234 // The connection is still connecting so it is no need to reset the 235 // connection state to disconnected. 236 // TODO b/220086369 will reset the connection immediately when requestConnection 237 // is called 238 if (mConnectionState != CONNECTING) { 239 setConnectionState(DISCONNECTED); 240 } 241 } 242 if (connection != null) { 243 mConnectionWrapper = new WindowMagnificationConnectionWrapper(connection, mTrace); 244 } 245 246 if (mConnectionWrapper != null) { 247 try { 248 mConnectionCallback = new ConnectionCallback(); 249 mConnectionWrapper.linkToDeath(mConnectionCallback); 250 mConnectionWrapper.setConnectionCallback(mConnectionCallback); 251 setConnectionState(CONNECTED); 252 } catch (RemoteException e) { 253 Slog.e(TAG, "setConnection failed", e); 254 mConnectionWrapper = null; 255 setConnectionState(DISCONNECTED); 256 } finally { 257 mLock.notify(); 258 } 259 } 260 } 261 } 262 263 /** 264 * @return {@code true} if {@link IWindowMagnificationConnection} is available 265 */ isConnected()266 public boolean isConnected() { 267 synchronized (mLock) { 268 return mConnectionWrapper != null; 269 } 270 } 271 272 /** 273 * Requests {@link IWindowMagnificationConnection} through 274 * {@link StatusBarManagerInternal#requestWindowMagnificationConnection(boolean)} and 275 * destroys all window magnifications if necessary. 276 * 277 * @param connect {@code true} if needs connection, otherwise set the connection to null and 278 * destroy all window magnifications. 279 * @return {@code true} if {@link IWindowMagnificationConnection} state is going to change. 280 */ requestConnection(boolean connect)281 public boolean requestConnection(boolean connect) { 282 if (DBG) { 283 Slog.d(TAG, "requestConnection :" + connect); 284 } 285 if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) { 286 mTrace.logTrace(TAG + ".requestWindowMagnificationConnection", 287 FLAGS_WINDOW_MAGNIFICATION_CONNECTION, "connect=" + connect); 288 } 289 synchronized (mLock) { 290 if ((connect && (mConnectionState == CONNECTED || mConnectionState == CONNECTING)) 291 || (!connect && (mConnectionState == DISCONNECTED 292 || mConnectionState == DISCONNECTING))) { 293 Slog.w(TAG, "requestConnection duplicated request: connect=" + connect 294 + ", mConnectionState=" + connectionStateToString(mConnectionState)); 295 return false; 296 } 297 298 if (connect) { 299 final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); 300 if (!mReceiverRegistered) { 301 mContext.registerReceiver(mScreenStateReceiver, intentFilter); 302 mReceiverRegistered = true; 303 } 304 } else { 305 disableAllWindowMagnifiers(); 306 if (mReceiverRegistered) { 307 mContext.unregisterReceiver(mScreenStateReceiver); 308 mReceiverRegistered = false; 309 } 310 } 311 } 312 if (requestConnectionInternal(connect)) { 313 setConnectionState(connect ? CONNECTING : DISCONNECTING); 314 return true; 315 } else { 316 setConnectionState(DISCONNECTED); 317 return false; 318 } 319 } 320 requestConnectionInternal(boolean connect)321 private boolean requestConnectionInternal(boolean connect) { 322 final long identity = Binder.clearCallingIdentity(); 323 try { 324 final StatusBarManagerInternal service = LocalServices.getService( 325 StatusBarManagerInternal.class); 326 if (service != null) { 327 return service.requestWindowMagnificationConnection(connect); 328 } 329 } finally { 330 Binder.restoreCallingIdentity(identity); 331 } 332 return false; 333 } 334 335 /** 336 * Returns window magnification connection state. 337 */ getConnectionState()338 public String getConnectionState() { 339 return connectionStateToString(mConnectionState); 340 } 341 setConnectionState(@onnectionState int state)342 private void setConnectionState(@ConnectionState int state) { 343 if (DBG) { 344 Slog.d(TAG, "setConnectionState : state=" + state + ", mConnectionState=" 345 + connectionStateToString(mConnectionState)); 346 } 347 mConnectionState = state; 348 } 349 350 /** 351 * Disables window magnifier on all displays without animation. 352 */ disableAllWindowMagnifiers()353 void disableAllWindowMagnifiers() { 354 synchronized (mLock) { 355 for (int i = 0; i < mWindowMagnifiers.size(); i++) { 356 final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i); 357 magnifier.disableWindowMagnificationInternal(null); 358 } 359 mWindowMagnifiers.clear(); 360 } 361 } 362 363 /** 364 * Resets the window magnifier on all displays that had been controlled by the 365 * specified service connection. Called when the service connection is unbound 366 * or binder died. 367 * 368 * @param connectionId The connection id 369 */ resetAllIfNeeded(int connectionId)370 public void resetAllIfNeeded(int connectionId) { 371 synchronized (mLock) { 372 for (int i = 0; i < mWindowMagnifiers.size(); i++) { 373 final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i); 374 if (magnifier != null 375 && magnifier.mEnabled 376 && connectionId == magnifier.getIdOfLastServiceToControl()) { 377 magnifier.disableWindowMagnificationInternal(null); 378 } 379 } 380 } 381 } 382 resetWindowMagnifiers()383 private void resetWindowMagnifiers() { 384 synchronized (mLock) { 385 for (int i = 0; i < mWindowMagnifiers.size(); i++) { 386 WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i); 387 magnifier.reset(); 388 } 389 } 390 } 391 392 @Override onRectangleOnScreenRequested(int displayId, int left, int top, int right, int bottom)393 public void onRectangleOnScreenRequested(int displayId, int left, int top, int right, 394 int bottom) { 395 if (!mMagnificationFollowTypingEnabled) { 396 return; 397 } 398 399 float toCenterX = (float) (left + right) / 2; 400 float toCenterY = (float) (top + bottom) / 2; 401 402 synchronized (mLock) { 403 if (mIsImeVisibleArray.get(displayId, false) 404 && !isPositionInSourceBounds(displayId, toCenterX, toCenterY) 405 && isTrackingTypingFocusEnabled(displayId)) { 406 moveWindowMagnifierToPositionInternal(displayId, toCenterX, toCenterY, 407 STUB_ANIMATION_CALLBACK); 408 } 409 } 410 } 411 setMagnificationFollowTypingEnabled(boolean enabled)412 void setMagnificationFollowTypingEnabled(boolean enabled) { 413 mMagnificationFollowTypingEnabled = enabled; 414 } 415 isMagnificationFollowTypingEnabled()416 boolean isMagnificationFollowTypingEnabled() { 417 return mMagnificationFollowTypingEnabled; 418 } 419 420 /** 421 * Get the ID of the last service that changed the magnification config. 422 * 423 * @param displayId The logical display id. 424 * @return The id 425 */ getIdOfLastServiceToMagnify(int displayId)426 public int getIdOfLastServiceToMagnify(int displayId) { 427 synchronized (mLock) { 428 final WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 429 if (magnifier != null) { 430 return magnifier.mIdOfLastServiceToControl; 431 } 432 } 433 return INVALID_SERVICE_ID; 434 } 435 436 /** 437 * Enable or disable tracking typing focus for the specific magnification window. 438 * 439 * The tracking typing focus should be set to enabled with the following conditions: 440 * 1. IME is shown. 441 * 442 * The tracking typing focus should be set to disabled with the following conditions: 443 * 1. A user drags the magnification window by 1 finger. 444 * 2. A user scroll the magnification window by 2 fingers. 445 * 446 * @param displayId The logical display id. 447 * @param trackingTypingFocusEnabled Enabled or disable the function of tracking typing focus. 448 */ setTrackingTypingFocusEnabled(int displayId, boolean trackingTypingFocusEnabled)449 void setTrackingTypingFocusEnabled(int displayId, boolean trackingTypingFocusEnabled) { 450 synchronized (mLock) { 451 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 452 if (magnifier == null) { 453 return; 454 } 455 magnifier.setTrackingTypingFocusEnabled(trackingTypingFocusEnabled); 456 } 457 } 458 459 /** 460 * Enable tracking typing focus function for all magnifications. 461 */ enableAllTrackingTypingFocus()462 private void enableAllTrackingTypingFocus() { 463 synchronized (mLock) { 464 for (int i = 0; i < mWindowMagnifiers.size(); i++) { 465 WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i); 466 magnifier.setTrackingTypingFocusEnabled(true); 467 } 468 } 469 } 470 pauseTrackingTypingFocusRecord(int displayId)471 private void pauseTrackingTypingFocusRecord(int displayId) { 472 WindowMagnifier magnifier; 473 synchronized (mLock) { 474 magnifier = mWindowMagnifiers.get(displayId); 475 if (magnifier == null) { 476 return; 477 } 478 } 479 magnifier.pauseTrackingTypingFocusRecord(); 480 } 481 482 /** 483 * Called when the IME window visibility changed. 484 * 485 * @param shown {@code true} means the IME window shows on the screen. Otherwise, it's hidden. 486 */ onImeWindowVisibilityChanged(int displayId, boolean shown)487 void onImeWindowVisibilityChanged(int displayId, boolean shown) { 488 synchronized (mLock) { 489 mIsImeVisibleArray.put(displayId, shown); 490 } 491 if (shown) { 492 enableAllTrackingTypingFocus(); 493 } else { 494 pauseTrackingTypingFocusRecord(displayId); 495 } 496 } 497 isImeVisible(int displayId)498 boolean isImeVisible(int displayId) { 499 synchronized (mLock) { 500 return mIsImeVisibleArray.get(displayId); 501 } 502 } 503 logTrackingTypingFocus(long duration)504 void logTrackingTypingFocus(long duration) { 505 AccessibilityStatsLogUtils.logMagnificationFollowTypingFocusSession(duration); 506 } 507 508 @Override processScroll(int displayId, float distanceX, float distanceY)509 public boolean processScroll(int displayId, float distanceX, float distanceY) { 510 moveWindowMagnification(displayId, -distanceX, -distanceY); 511 setTrackingTypingFocusEnabled(displayId, false); 512 return /* event consumed: */ true; 513 } 514 515 /** 516 * Scales the magnified region on the specified display if window magnification is initiated. 517 * 518 * @param displayId The logical display id. 519 * @param scale The target scale, must be >= 1 520 */ 521 @Override setScale(int displayId, float scale)522 public void setScale(int displayId, float scale) { 523 synchronized (mLock) { 524 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 525 if (magnifier == null) { 526 return; 527 } 528 magnifier.setScale(scale); 529 } 530 } 531 532 /** 533 * Enables window magnification with specified center and scale on the given display and 534 * animating the transition. 535 * 536 * @param displayId The logical display id. 537 * @param scale The target scale, must be >= 1. 538 * @param centerX The screen-relative X coordinate around which to center, 539 * or {@link Float#NaN} to leave unchanged. 540 * @param centerY The screen-relative Y coordinate around which to center, 541 * or {@link Float#NaN} to leave unchanged. 542 * @return {@code true} if the magnification is enabled successfully. 543 */ enableWindowMagnification(int displayId, float scale, float centerX, float centerY)544 public boolean enableWindowMagnification(int displayId, float scale, float centerX, 545 float centerY) { 546 return enableWindowMagnification(displayId, scale, centerX, centerY, 547 STUB_ANIMATION_CALLBACK, MAGNIFICATION_GESTURE_HANDLER_ID); 548 } 549 550 /** 551 * Enables window magnification with specified center and scale on the given display and 552 * animating the transition. 553 * 554 * @param displayId The logical display id. 555 * @param scale The target scale, must be >= 1. 556 * @param centerX The screen-relative X coordinate around which to center for magnification, 557 * or {@link Float#NaN} to leave unchanged. 558 * @param centerY The screen-relative Y coordinate around which to center for magnification, 559 * or {@link Float#NaN} to leave unchanged. 560 * @param animationCallback Called when the animation result is valid. 561 * @param id The connection ID 562 * @return {@code true} if the magnification is enabled successfully. 563 */ enableWindowMagnification(int displayId, float scale, float centerX, float centerY, @Nullable MagnificationAnimationCallback animationCallback, int id)564 public boolean enableWindowMagnification(int displayId, float scale, float centerX, 565 float centerY, @Nullable MagnificationAnimationCallback animationCallback, int id) { 566 return enableWindowMagnification(displayId, scale, centerX, centerY, animationCallback, 567 WINDOW_POSITION_AT_CENTER, id); 568 } 569 570 /** 571 * Enables window magnification with specified center and scale on the given display and 572 * animating the transition. 573 * 574 * @param displayId The logical display id. 575 * @param scale The target scale, must be >= 1. 576 * @param centerX The screen-relative X coordinate around which to center for magnification, 577 * or {@link Float#NaN} to leave unchanged. 578 * @param centerY The screen-relative Y coordinate around which to center for magnification, 579 * or {@link Float#NaN} to leave unchanged. 580 * @param windowPosition Indicate the offset between window position and (centerX, centerY). 581 * @return {@code true} if the magnification is enabled successfully. 582 */ enableWindowMagnification(int displayId, float scale, float centerX, float centerY, @WindowPosition int windowPosition)583 public boolean enableWindowMagnification(int displayId, float scale, float centerX, 584 float centerY, @WindowPosition int windowPosition) { 585 return enableWindowMagnification(displayId, scale, centerX, centerY, 586 STUB_ANIMATION_CALLBACK, windowPosition, MAGNIFICATION_GESTURE_HANDLER_ID); 587 } 588 589 /** 590 * Enables window magnification with specified center and scale on the given display and 591 * animating the transition. 592 * 593 * @param displayId The logical display id. 594 * @param scale The target scale, must be >= 1. 595 * @param centerX The screen-relative X coordinate around which to center for 596 * magnification, or {@link Float#NaN} to leave unchanged. 597 * @param centerY The screen-relative Y coordinate around which to center for 598 * magnification, or {@link Float#NaN} to leave unchanged. 599 * @param animationCallback Called when the animation result is valid. 600 * @param windowPosition Indicate the offset between window position and (centerX, centerY). 601 * @return {@code true} if the magnification is enabled successfully. 602 */ enableWindowMagnification(int displayId, float scale, float centerX, float centerY, @Nullable MagnificationAnimationCallback animationCallback, @WindowPosition int windowPosition, int id)603 public boolean enableWindowMagnification(int displayId, float scale, float centerX, 604 float centerY, @Nullable MagnificationAnimationCallback animationCallback, 605 @WindowPosition int windowPosition, int id) { 606 final boolean enabled; 607 boolean previousEnabled; 608 synchronized (mLock) { 609 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 610 if (magnifier == null) { 611 magnifier = createWindowMagnifier(displayId); 612 } 613 previousEnabled = magnifier.mEnabled; 614 enabled = magnifier.enableWindowMagnificationInternal(scale, centerX, centerY, 615 animationCallback, windowPosition, id); 616 } 617 618 if (enabled) { 619 setTrackingTypingFocusEnabled(displayId, true); 620 if (!previousEnabled) { 621 mCallback.onWindowMagnificationActivationState(displayId, true); 622 } 623 } 624 return enabled; 625 } 626 627 /** 628 * Disables window magnification on the given display. 629 * 630 * @param displayId The logical display id. 631 * @param clear {@true} Clears the state of window magnification. 632 * @return {@code true} if the magnification is turned to be disabled successfully 633 */ disableWindowMagnification(int displayId, boolean clear)634 boolean disableWindowMagnification(int displayId, boolean clear) { 635 return disableWindowMagnification(displayId, clear, STUB_ANIMATION_CALLBACK); 636 } 637 638 /** 639 * Disables window magnification on the specified display and animating the transition. 640 * 641 * @param displayId The logical display id. 642 * @param clear {@true} Clears the state of window magnification. 643 * @param animationCallback Called when the animation result is valid. 644 * @return {@code true} if the magnification is turned to be disabled successfully 645 */ disableWindowMagnification(int displayId, boolean clear, MagnificationAnimationCallback animationCallback)646 public boolean disableWindowMagnification(int displayId, boolean clear, 647 MagnificationAnimationCallback animationCallback) { 648 final boolean disabled; 649 synchronized (mLock) { 650 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 651 if (magnifier == null) { 652 return false; 653 } 654 655 disabled = magnifier.disableWindowMagnificationInternal(animationCallback); 656 if (clear) { 657 mWindowMagnifiers.delete(displayId); 658 } 659 } 660 661 if (disabled) { 662 mCallback.onWindowMagnificationActivationState(displayId, false); 663 } 664 return disabled; 665 } 666 667 /** 668 * Calculates the number of fingers in the window. 669 * 670 * @param displayId The logical display id. 671 * @param motionEvent The motion event 672 * @return the number of fingers in the window. 673 */ pointersInWindow(int displayId, MotionEvent motionEvent)674 int pointersInWindow(int displayId, MotionEvent motionEvent) { 675 synchronized (mLock) { 676 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 677 if (magnifier == null) { 678 return 0; 679 } 680 return magnifier.pointersInWindow(motionEvent); 681 } 682 } 683 684 @GuardedBy("mLock") isPositionInSourceBounds(int displayId, float x, float y)685 boolean isPositionInSourceBounds(int displayId, float x, float y) { 686 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 687 if (magnifier == null) { 688 return false; 689 } 690 return magnifier.isPositionInSourceBounds(x, y); 691 } 692 693 /** 694 * Indicates whether window magnification is enabled on specified display. 695 * 696 * @param displayId The logical display id. 697 * @return {@code true} if the window magnification is enabled. 698 */ 699 @VisibleForTesting isWindowMagnifierEnabled(int displayId)700 public boolean isWindowMagnifierEnabled(int displayId) { 701 synchronized (mLock) { 702 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 703 if (magnifier == null) { 704 return false; 705 } 706 return magnifier.isEnabled(); 707 } 708 } 709 710 /** 711 * Retrieves a previously magnification scale from the current 712 * user's settings. Only the value of the default display is persisted. 713 * 714 * @return the previously magnification scale, or the default 715 * scale if none is available 716 */ getPersistedScale(int displayId)717 float getPersistedScale(int displayId) { 718 return mScaleProvider.getScale(displayId); 719 } 720 721 /** 722 * Persists the default display magnification scale to the current user's settings. Only the 723 * value of the default display is persisted in user's settings. 724 */ persistScale(int displayId)725 void persistScale(int displayId) { 726 float scale = getScale(displayId); 727 if (scale != 1.0f) { 728 mScaleProvider.putScale(scale, displayId); 729 } 730 } 731 732 /** 733 * Returns the magnification scale. 734 * 735 * @param displayId The logical display id. 736 * @return the scale 737 */ getScale(int displayId)738 public float getScale(int displayId) { 739 synchronized (mLock) { 740 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 741 if (magnifier == null || !magnifier.mEnabled) { 742 return 1.0f; 743 } 744 return magnifier.getScale(); 745 } 746 } 747 748 /** 749 * Moves window magnification on the specified display with the specified offset. 750 * 751 * @param displayId The logical display id. 752 * @param offsetX the amount in pixels to offset the region in the X direction, in current 753 * screen pixels. 754 * @param offsetY the amount in pixels to offset the region in the Y direction, in current 755 * screen pixels. 756 */ moveWindowMagnification(int displayId, float offsetX, float offsetY)757 void moveWindowMagnification(int displayId, float offsetX, float offsetY) { 758 synchronized (mLock) { 759 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 760 if (magnifier == null) { 761 return; 762 } 763 magnifier.move(offsetX, offsetY); 764 } 765 } 766 767 /** 768 * Requests System UI show magnification mode button UI on the specified display. 769 * 770 * @param displayId The logical display id. 771 * @param magnificationMode the current magnification mode. 772 * @return {@code true} if the event was handled, {@code false} otherwise 773 */ showMagnificationButton(int displayId, int magnificationMode)774 public boolean showMagnificationButton(int displayId, int magnificationMode) { 775 return mConnectionWrapper != null && mConnectionWrapper.showMagnificationButton( 776 displayId, magnificationMode); 777 } 778 779 /** 780 * Requests System UI remove magnification mode button UI on the specified display. 781 * 782 * @param displayId The logical display id. 783 * @return {@code true} if the event was handled, {@code false} otherwise 784 */ removeMagnificationButton(int displayId)785 public boolean removeMagnificationButton(int displayId) { 786 return mConnectionWrapper != null && mConnectionWrapper.removeMagnificationButton( 787 displayId); 788 } 789 790 /** 791 * Returns the screen-relative X coordinate of the center of the magnified bounds. 792 * 793 * @param displayId The logical display id 794 * @return the X coordinate. {@link Float#NaN} if the window magnification is not enabled. 795 */ getCenterX(int displayId)796 public float getCenterX(int displayId) { 797 synchronized (mLock) { 798 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 799 if (magnifier == null || !magnifier.mEnabled) { 800 return Float.NaN; 801 } 802 return magnifier.getCenterX(); 803 } 804 } 805 806 /** 807 * Returns the screen-relative Y coordinate of the center of the magnified bounds. 808 * 809 * @param displayId The logical display id 810 * @return the Y coordinate. {@link Float#NaN} if the window magnification is not enabled. 811 */ getCenterY(int displayId)812 public float getCenterY(int displayId) { 813 synchronized (mLock) { 814 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 815 if (magnifier == null || !magnifier.mEnabled) { 816 return Float.NaN; 817 } 818 return magnifier.getCenterY(); 819 } 820 } 821 isTrackingTypingFocusEnabled(int displayId)822 boolean isTrackingTypingFocusEnabled(int displayId) { 823 synchronized (mLock) { 824 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 825 if (magnifier == null) { 826 return false; 827 } 828 return magnifier.isTrackingTypingFocusEnabled(); 829 } 830 } 831 832 /** 833 * Populates magnified bounds on the screen. And the populated magnified bounds would be 834 * empty If window magnifier is not activated. 835 * 836 * @param displayId The logical display id. 837 * @param outRegion the region to populate 838 */ getMagnificationSourceBounds(int displayId, @NonNull Region outRegion)839 public void getMagnificationSourceBounds(int displayId, @NonNull Region outRegion) { 840 synchronized (mLock) { 841 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 842 if (magnifier == null || !magnifier.mEnabled) { 843 outRegion.setEmpty(); 844 } else { 845 outRegion.set(magnifier.mSourceBounds); 846 } 847 } 848 } 849 850 /** 851 * Creates the windowMagnifier based on the specified display and stores it. 852 * 853 * @param displayId logical display id. 854 */ 855 @GuardedBy("mLock") createWindowMagnifier(int displayId)856 private WindowMagnifier createWindowMagnifier(int displayId) { 857 final WindowMagnifier magnifier = new WindowMagnifier(displayId, this); 858 mWindowMagnifiers.put(displayId, magnifier); 859 return magnifier; 860 } 861 862 /** 863 * Removes the window magnifier with given id. 864 * 865 * @param displayId The logical display id. 866 */ onDisplayRemoved(int displayId)867 public void onDisplayRemoved(int displayId) { 868 disableWindowMagnification(displayId, true); 869 } 870 871 private class ConnectionCallback extends IWindowMagnificationConnectionCallback.Stub implements 872 IBinder.DeathRecipient { 873 private boolean mExpiredDeathRecipient = false; 874 875 @Override onWindowMagnifierBoundsChanged(int displayId, Rect bounds)876 public void onWindowMagnifierBoundsChanged(int displayId, Rect bounds) { 877 if (mTrace.isA11yTracingEnabledForTypes( 878 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) { 879 mTrace.logTrace(TAG + "ConnectionCallback.onWindowMagnifierBoundsChanged", 880 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK, 881 "displayId=" + displayId + ";bounds=" + bounds); 882 } 883 synchronized (mLock) { 884 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 885 if (magnifier == null) { 886 magnifier = createWindowMagnifier(displayId); 887 } 888 if (DBG) { 889 Slog.i(TAG, 890 "onWindowMagnifierBoundsChanged -" + displayId + " bounds = " + bounds); 891 } 892 magnifier.setMagnifierLocation(bounds); 893 } 894 } 895 896 @Override onChangeMagnificationMode(int displayId, int magnificationMode)897 public void onChangeMagnificationMode(int displayId, int magnificationMode) 898 throws RemoteException { 899 if (mTrace.isA11yTracingEnabledForTypes( 900 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) { 901 mTrace.logTrace(TAG + "ConnectionCallback.onChangeMagnificationMode", 902 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK, 903 "displayId=" + displayId + ";mode=" + magnificationMode); 904 } 905 mCallback.onChangeMagnificationMode(displayId, magnificationMode); 906 } 907 908 @Override onSourceBoundsChanged(int displayId, Rect sourceBounds)909 public void onSourceBoundsChanged(int displayId, Rect sourceBounds) { 910 if (mTrace.isA11yTracingEnabledForTypes( 911 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) { 912 mTrace.logTrace(TAG + "ConnectionCallback.onSourceBoundsChanged", 913 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK, 914 "displayId=" + displayId + ";source=" + sourceBounds); 915 } 916 synchronized (mLock) { 917 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 918 if (magnifier == null) { 919 magnifier = createWindowMagnifier(displayId); 920 } 921 magnifier.onSourceBoundsChanged(sourceBounds); 922 } 923 mCallback.onSourceBoundsChanged(displayId, sourceBounds); 924 } 925 926 @Override onPerformScaleAction(int displayId, float scale)927 public void onPerformScaleAction(int displayId, float scale) { 928 if (mTrace.isA11yTracingEnabledForTypes( 929 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) { 930 mTrace.logTrace(TAG + "ConnectionCallback.onPerformScaleAction", 931 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK, 932 "displayId=" + displayId + ";scale=" + scale); 933 } 934 mCallback.onPerformScaleAction(displayId, scale); 935 } 936 937 @Override onAccessibilityActionPerformed(int displayId)938 public void onAccessibilityActionPerformed(int displayId) { 939 if (mTrace.isA11yTracingEnabledForTypes( 940 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) { 941 mTrace.logTrace(TAG + "ConnectionCallback.onAccessibilityActionPerformed", 942 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK, 943 "displayId=" + displayId); 944 } 945 mCallback.onAccessibilityActionPerformed(displayId); 946 } 947 948 @Override onMove(int displayId)949 public void onMove(int displayId) { 950 if (mTrace.isA11yTracingEnabledForTypes( 951 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) { 952 mTrace.logTrace(TAG + "ConnectionCallback.onMove", 953 FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK, 954 "displayId=" + displayId); 955 } 956 setTrackingTypingFocusEnabled(displayId, false); 957 } 958 959 @Override binderDied()960 public void binderDied() { 961 synchronized (mLock) { 962 Slog.w(TAG, "binderDied DeathRecipient :" + mExpiredDeathRecipient); 963 if (mExpiredDeathRecipient) { 964 return; 965 } 966 mConnectionWrapper.unlinkToDeath(this); 967 mConnectionWrapper = null; 968 mConnectionCallback = null; 969 setConnectionState(DISCONNECTED); 970 resetWindowMagnifiers(); 971 } 972 } 973 } 974 975 /** 976 * A class manipulates window magnification per display and contains the magnification 977 * information. 978 * <p> 979 * This class requires to hold the lock when controlling the magnifier. 980 * </p> 981 */ 982 private static class WindowMagnifier { 983 984 private final int mDisplayId; 985 private float mScale = MagnificationScaleProvider.MIN_SCALE; 986 private boolean mEnabled; 987 988 private final WindowMagnificationManager mWindowMagnificationManager; 989 // Records the bounds of window magnification. 990 private final Rect mBounds = new Rect(); 991 // The magnified bounds on the screen. 992 private final Rect mSourceBounds = new Rect(); 993 994 private int mIdOfLastServiceToControl = INVALID_SERVICE_ID; 995 996 private final PointF mMagnificationFrameOffsetRatio = new PointF(0f, 0f); 997 998 private boolean mTrackingTypingFocusEnabled = true; 999 1000 private volatile long mTrackingTypingFocusStartTime = 0; 1001 private static final AtomicLongFieldUpdater<WindowMagnifier> SUM_TIME_UPDATER = 1002 AtomicLongFieldUpdater.newUpdater(WindowMagnifier.class, 1003 "mTrackingTypingFocusSumTime"); 1004 private volatile long mTrackingTypingFocusSumTime = 0; 1005 WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager)1006 WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) { 1007 mDisplayId = displayId; 1008 mWindowMagnificationManager = windowMagnificationManager; 1009 } 1010 enableWindowMagnificationInternal(float scale, float centerX, float centerY, @Nullable MagnificationAnimationCallback animationCallback, @WindowPosition int windowPosition, int id)1011 boolean enableWindowMagnificationInternal(float scale, float centerX, float centerY, 1012 @Nullable MagnificationAnimationCallback animationCallback, 1013 @WindowPosition int windowPosition, int id) { 1014 // Handle defaults. The scale may be NAN when just updating magnification center. 1015 if (Float.isNaN(scale)) { 1016 scale = getScale(); 1017 } 1018 final float normScale = MagnificationScaleProvider.constrainScale(scale); 1019 setMagnificationFrameOffsetRatioByWindowPosition(windowPosition); 1020 if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale, 1021 centerX, centerY, mMagnificationFrameOffsetRatio.x, 1022 mMagnificationFrameOffsetRatio.y, animationCallback)) { 1023 mScale = normScale; 1024 mEnabled = true; 1025 mIdOfLastServiceToControl = id; 1026 return true; 1027 } 1028 return false; 1029 } 1030 setMagnificationFrameOffsetRatioByWindowPosition(@indowPosition int windowPosition)1031 void setMagnificationFrameOffsetRatioByWindowPosition(@WindowPosition int windowPosition) { 1032 switch (windowPosition) { 1033 case WINDOW_POSITION_AT_CENTER: { 1034 mMagnificationFrameOffsetRatio.set(0f, 0f); 1035 } 1036 break; 1037 case WINDOW_POSITION_AT_TOP_LEFT: { 1038 mMagnificationFrameOffsetRatio.set(-1f, -1f); 1039 } 1040 break; 1041 } 1042 } 1043 disableWindowMagnificationInternal( @ullable MagnificationAnimationCallback animationResultCallback)1044 boolean disableWindowMagnificationInternal( 1045 @Nullable MagnificationAnimationCallback animationResultCallback) { 1046 if (!mEnabled) { 1047 return false; 1048 } 1049 if (mWindowMagnificationManager.disableWindowMagnificationInternal( 1050 mDisplayId, animationResultCallback)) { 1051 mEnabled = false; 1052 mIdOfLastServiceToControl = INVALID_SERVICE_ID; 1053 mTrackingTypingFocusEnabled = false; 1054 pauseTrackingTypingFocusRecord(); 1055 return true; 1056 } 1057 return false; 1058 } 1059 1060 @GuardedBy("mLock") setScale(float scale)1061 void setScale(float scale) { 1062 if (!mEnabled) { 1063 return; 1064 } 1065 final float normScale = MagnificationScaleProvider.constrainScale(scale); 1066 if (Float.compare(mScale, normScale) != 0 1067 && mWindowMagnificationManager.setScaleInternal(mDisplayId, scale)) { 1068 mScale = normScale; 1069 } 1070 } 1071 1072 @GuardedBy("mLock") getScale()1073 float getScale() { 1074 return mScale; 1075 } 1076 1077 @GuardedBy("mLock") setMagnifierLocation(Rect rect)1078 void setMagnifierLocation(Rect rect) { 1079 mBounds.set(rect); 1080 } 1081 1082 /** 1083 * Returns the ID of the last service that changed the magnification config. 1084 */ getIdOfLastServiceToControl()1085 int getIdOfLastServiceToControl() { 1086 return mIdOfLastServiceToControl; 1087 } 1088 pointersInWindow(MotionEvent motionEvent)1089 int pointersInWindow(MotionEvent motionEvent) { 1090 int count = 0; 1091 final int pointerCount = motionEvent.getPointerCount(); 1092 for (int i = 0; i < pointerCount; i++) { 1093 final float x = motionEvent.getX(i); 1094 final float y = motionEvent.getY(i); 1095 if (mBounds.contains((int) x, (int) y)) { 1096 count++; 1097 } 1098 } 1099 return count; 1100 } 1101 isPositionInSourceBounds(float x, float y)1102 boolean isPositionInSourceBounds(float x, float y) { 1103 return mSourceBounds.contains((int) x, (int) y); 1104 } 1105 setTrackingTypingFocusEnabled(boolean trackingTypingFocusEnabled)1106 void setTrackingTypingFocusEnabled(boolean trackingTypingFocusEnabled) { 1107 if (mWindowMagnificationManager.isWindowMagnifierEnabled(mDisplayId) 1108 && mWindowMagnificationManager.isImeVisible(mDisplayId) 1109 && trackingTypingFocusEnabled) { 1110 startTrackingTypingFocusRecord(); 1111 } 1112 if (mTrackingTypingFocusEnabled && !trackingTypingFocusEnabled) { 1113 stopAndLogTrackingTypingFocusRecordIfNeeded(); 1114 } 1115 mTrackingTypingFocusEnabled = trackingTypingFocusEnabled; 1116 } 1117 isTrackingTypingFocusEnabled()1118 boolean isTrackingTypingFocusEnabled() { 1119 return mTrackingTypingFocusEnabled; 1120 } 1121 startTrackingTypingFocusRecord()1122 void startTrackingTypingFocusRecord() { 1123 if (mTrackingTypingFocusStartTime == 0) { 1124 mTrackingTypingFocusStartTime = SystemClock.uptimeMillis(); 1125 if (DBG) { 1126 Slog.d(TAG, "start: mTrackingTypingFocusStartTime = " 1127 + mTrackingTypingFocusStartTime); 1128 } 1129 } 1130 } 1131 pauseTrackingTypingFocusRecord()1132 void pauseTrackingTypingFocusRecord() { 1133 if (mTrackingTypingFocusStartTime != 0) { 1134 final long elapsed = (SystemClock.uptimeMillis() - mTrackingTypingFocusStartTime); 1135 // update mTrackingTypingFocusSumTime value in an atomic operation 1136 SUM_TIME_UPDATER.addAndGet(this, elapsed); 1137 mTrackingTypingFocusStartTime = 0; 1138 if (DBG) { 1139 Slog.d(TAG, "pause: mTrackingTypingFocusSumTime = " 1140 + mTrackingTypingFocusSumTime + ", elapsed = " + elapsed); 1141 } 1142 } 1143 } 1144 stopAndLogTrackingTypingFocusRecordIfNeeded()1145 void stopAndLogTrackingTypingFocusRecordIfNeeded() { 1146 if (mTrackingTypingFocusStartTime != 0 || mTrackingTypingFocusSumTime != 0) { 1147 final long elapsed = mTrackingTypingFocusStartTime != 0 1148 ? (SystemClock.uptimeMillis() - mTrackingTypingFocusStartTime) : 0; 1149 final long duration = mTrackingTypingFocusSumTime + elapsed; 1150 if (DBG) { 1151 Slog.d(TAG, "stop and log: session duration = " + duration 1152 + ", elapsed = " + elapsed); 1153 } 1154 mWindowMagnificationManager.logTrackingTypingFocus(duration); 1155 mTrackingTypingFocusStartTime = 0; 1156 mTrackingTypingFocusSumTime = 0; 1157 } 1158 } 1159 isEnabled()1160 boolean isEnabled() { 1161 return mEnabled; 1162 } 1163 1164 @GuardedBy("mLock") move(float offsetX, float offsetY)1165 void move(float offsetX, float offsetY) { 1166 mWindowMagnificationManager.moveWindowMagnifierInternal(mDisplayId, offsetX, offsetY); 1167 } 1168 1169 @GuardedBy("mLock") reset()1170 void reset() { 1171 mEnabled = false; 1172 mIdOfLastServiceToControl = INVALID_SERVICE_ID; 1173 mSourceBounds.setEmpty(); 1174 } 1175 1176 @GuardedBy("mLock") onSourceBoundsChanged(Rect sourceBounds)1177 public void onSourceBoundsChanged(Rect sourceBounds) { 1178 mSourceBounds.set(sourceBounds); 1179 } 1180 1181 @GuardedBy("mLock") getCenterX()1182 float getCenterX() { 1183 return mSourceBounds.exactCenterX(); 1184 } 1185 1186 @GuardedBy("mLock") getCenterY()1187 float getCenterY() { 1188 return mSourceBounds.exactCenterY(); 1189 } 1190 } 1191 1192 @GuardedBy("mLock") enableWindowMagnificationInternal(int displayId, float scale, float centerX, float centerY, float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY, MagnificationAnimationCallback animationCallback)1193 private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX, 1194 float centerY, float magnificationFrameOffsetRatioX, 1195 float magnificationFrameOffsetRatioY, 1196 MagnificationAnimationCallback animationCallback) { 1197 // Wait for the connection with a timeout. 1198 final long endMillis = SystemClock.uptimeMillis() + WAIT_CONNECTION_TIMEOUT_MILLIS; 1199 while (mConnectionState == CONNECTING && (SystemClock.uptimeMillis() < endMillis)) { 1200 try { 1201 mLock.wait(endMillis - SystemClock.uptimeMillis()); 1202 } catch (InterruptedException ie) { 1203 /* ignore */ 1204 } 1205 } 1206 if (mConnectionWrapper == null) { 1207 Slog.w(TAG, 1208 "enableWindowMagnificationInternal mConnectionWrapper is null. " 1209 + "mConnectionState=" + connectionStateToString(mConnectionState)); 1210 return false; 1211 } 1212 return mConnectionWrapper.enableWindowMagnification( 1213 displayId, scale, centerX, centerY, 1214 magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY, 1215 animationCallback); 1216 } 1217 setScaleInternal(int displayId, float scale)1218 private boolean setScaleInternal(int displayId, float scale) { 1219 return mConnectionWrapper != null && mConnectionWrapper.setScale(displayId, scale); 1220 } 1221 1222 @GuardedBy("mLock") disableWindowMagnificationInternal(int displayId, MagnificationAnimationCallback animationCallback)1223 private boolean disableWindowMagnificationInternal(int displayId, 1224 MagnificationAnimationCallback animationCallback) { 1225 if (mConnectionWrapper == null) { 1226 Slog.w(TAG, "mConnectionWrapper is null"); 1227 return false; 1228 } 1229 return mConnectionWrapper.disableWindowMagnification( 1230 displayId, animationCallback); 1231 } 1232 1233 @GuardedBy("mLock") moveWindowMagnifierInternal(int displayId, float offsetX, float offsetY)1234 private boolean moveWindowMagnifierInternal(int displayId, float offsetX, float offsetY) { 1235 return mConnectionWrapper != null && mConnectionWrapper.moveWindowMagnifier( 1236 displayId, offsetX, offsetY); 1237 } 1238 1239 @GuardedBy("mLock") moveWindowMagnifierToPositionInternal(int displayId, float positionX, float positionY, MagnificationAnimationCallback animationCallback)1240 private boolean moveWindowMagnifierToPositionInternal(int displayId, float positionX, 1241 float positionY, MagnificationAnimationCallback animationCallback) { 1242 return mConnectionWrapper != null && mConnectionWrapper.moveWindowMagnifierToPosition( 1243 displayId, positionX, positionY, animationCallback); 1244 } 1245 } 1246