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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.graphics.Rect; 26 import android.os.Binder; 27 import android.os.IBinder; 28 import android.os.RemoteException; 29 import android.provider.Settings; 30 import android.util.MathUtils; 31 import android.util.Slog; 32 import android.util.SparseArray; 33 import android.view.MotionEvent; 34 import android.view.accessibility.IWindowMagnificationConnection; 35 import android.view.accessibility.IWindowMagnificationConnectionCallback; 36 import android.view.accessibility.MagnificationAnimationCallback; 37 38 import com.android.internal.annotations.GuardedBy; 39 import com.android.internal.annotations.VisibleForTesting; 40 import com.android.internal.os.BackgroundThread; 41 import com.android.server.LocalServices; 42 import com.android.server.statusbar.StatusBarManagerInternal; 43 44 /** 45 * A class to manipulate window magnification through {@link WindowMagnificationConnectionWrapper} 46 * create by {@link #setConnection(IWindowMagnificationConnection)}. To set the connection with 47 * SysUI, call {@code StatusBarManagerInternal#requestWindowMagnificationConnection(boolean)}. 48 */ 49 public class WindowMagnificationManager implements 50 PanningScalingHandler.MagnificationDelegate { 51 52 private static final boolean DBG = false; 53 54 private static final String TAG = "WindowMagnificationMgr"; 55 56 //Ensure the range has consistency with full screen. 57 static final float MAX_SCALE = FullScreenMagnificationController.MAX_SCALE; 58 static final float MIN_SCALE = FullScreenMagnificationController.MIN_SCALE; 59 60 private final Object mLock = new Object(); 61 private final Context mContext; 62 @VisibleForTesting 63 @GuardedBy("mLock") 64 @Nullable 65 WindowMagnificationConnectionWrapper mConnectionWrapper; 66 @GuardedBy("mLock") 67 private ConnectionCallback mConnectionCallback; 68 @GuardedBy("mLock") 69 private SparseArray<WindowMagnifier> mWindowMagnifiers = new SparseArray<>(); 70 private int mUserId; 71 72 private boolean mReceiverRegistered = false; 73 @VisibleForTesting 74 protected final BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() { 75 @Override 76 public void onReceive(Context context, Intent intent) { 77 final int displayId = context.getDisplayId(); 78 removeMagnificationButton(displayId); 79 disableWindowMagnification(displayId, false); 80 } 81 }; 82 83 /** 84 * Callback to handle magnification actions from system UI. 85 */ 86 public interface Callback { 87 88 /** 89 * Called when the accessibility action of scale requests to be performed. 90 * It is invoked from System UI. And the action is provided by the mirror window. 91 * 92 * @param displayId The logical display id. 93 * @param scale the target scale, or {@link Float#NaN} to leave unchanged 94 */ onPerformScaleAction(int displayId, float scale)95 void onPerformScaleAction(int displayId, float scale); 96 97 /** 98 * Called when the accessibility action is performed. 99 * 100 * @param displayId The logical display id. 101 */ onAccessibilityActionPerformed(int displayId)102 void onAccessibilityActionPerformed(int displayId); 103 104 /** 105 * Called when the state of the magnification activation is changed. 106 * 107 * @param displayId The logical display id. 108 * @param activated {@code true} if the magnification is activated, otherwise {@code false}. 109 */ onWindowMagnificationActivationState(int displayId, boolean activated)110 void onWindowMagnificationActivationState(int displayId, boolean activated); 111 } 112 113 private final Callback mCallback; 114 WindowMagnificationManager(Context context, int userId, @NonNull Callback callback)115 public WindowMagnificationManager(Context context, int userId, @NonNull Callback callback) { 116 mContext = context; 117 mUserId = userId; 118 mCallback = callback; 119 } 120 121 /** 122 * Sets {@link IWindowMagnificationConnection}. 123 * 124 * @param connection {@link IWindowMagnificationConnection} 125 */ setConnection(@ullable IWindowMagnificationConnection connection)126 public void setConnection(@Nullable IWindowMagnificationConnection connection) { 127 synchronized (mLock) { 128 // Reset connectionWrapper. 129 if (mConnectionWrapper != null) { 130 mConnectionWrapper.setConnectionCallback(null); 131 if (mConnectionCallback != null) { 132 mConnectionCallback.mExpiredDeathRecipient = true; 133 } 134 mConnectionWrapper.unlinkToDeath(mConnectionCallback); 135 mConnectionWrapper = null; 136 } 137 if (connection != null) { 138 mConnectionWrapper = new WindowMagnificationConnectionWrapper(connection); 139 } 140 141 if (mConnectionWrapper != null) { 142 try { 143 mConnectionCallback = new ConnectionCallback(); 144 mConnectionWrapper.linkToDeath(mConnectionCallback); 145 mConnectionWrapper.setConnectionCallback(mConnectionCallback); 146 } catch (RemoteException e) { 147 Slog.e(TAG, "setConnection failed", e); 148 mConnectionWrapper = null; 149 } 150 } 151 } 152 } 153 154 /** 155 * Sets the currently active user ID. 156 * 157 * @param userId the currently active user ID 158 */ setUserId(int userId)159 public void setUserId(int userId) { 160 mUserId = userId; 161 } 162 163 /** 164 * @return {@code true} if {@link IWindowMagnificationConnection} is available 165 */ isConnected()166 public boolean isConnected() { 167 synchronized (mLock) { 168 return mConnectionWrapper != null; 169 } 170 } 171 172 /** 173 * Requests {@link IWindowMagnificationConnection} through 174 * {@link StatusBarManagerInternal#requestWindowMagnificationConnection(boolean)} and 175 * destroys all window magnifications if necessary. 176 * 177 * @param connect {@code true} if needs connection, otherwise set the connection to null and 178 * destroy all window magnifications. 179 * @return {@code true} if {@link IWindowMagnificationConnection} state is going to change. 180 */ requestConnection(boolean connect)181 public boolean requestConnection(boolean connect) { 182 synchronized (mLock) { 183 if (connect == isConnected()) { 184 return false; 185 } 186 if (connect) { 187 final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); 188 if (!mReceiverRegistered) { 189 mContext.registerReceiver(mScreenStateReceiver, intentFilter); 190 mReceiverRegistered = true; 191 } 192 } else { 193 disableAllWindowMagnifiers(); 194 if (mReceiverRegistered) { 195 mContext.unregisterReceiver(mScreenStateReceiver); 196 mReceiverRegistered = false; 197 } 198 } 199 } 200 201 final long identity = Binder.clearCallingIdentity(); 202 try { 203 final StatusBarManagerInternal service = LocalServices.getService( 204 StatusBarManagerInternal.class); 205 service.requestWindowMagnificationConnection(connect); 206 } finally { 207 Binder.restoreCallingIdentity(identity); 208 } 209 return true; 210 } 211 212 @GuardedBy("mLock") disableAllWindowMagnifiers()213 private void disableAllWindowMagnifiers() { 214 for (int i = 0; i < mWindowMagnifiers.size(); i++) { 215 final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i); 216 magnifier.disableWindowMagnificationInternal(null); 217 } 218 mWindowMagnifiers.clear(); 219 } 220 resetWindowMagnifiers()221 private void resetWindowMagnifiers() { 222 synchronized (mLock) { 223 for (int i = 0; i < mWindowMagnifiers.size(); i++) { 224 WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i); 225 magnifier.reset(); 226 } 227 } 228 } 229 230 @Override processScroll(int displayId, float distanceX, float distanceY)231 public boolean processScroll(int displayId, float distanceX, float distanceY) { 232 moveWindowMagnification(displayId, -distanceX, -distanceY); 233 return /* event consumed: */ true; 234 } 235 236 /** 237 * Scales the magnified region on the specified display if window magnification is initiated. 238 * 239 * @param displayId The logical display id. 240 * @param scale The target scale, must be >= 1 241 */ 242 @Override setScale(int displayId, float scale)243 public void setScale(int displayId, float scale) { 244 synchronized (mLock) { 245 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 246 if (magnifier == null) { 247 return; 248 } 249 magnifier.setScale(scale); 250 } 251 } 252 253 /** 254 * Enables window magnification with specified center and scale on the given display and 255 * animating the transition. 256 * 257 * @param displayId The logical display id. 258 * @param scale The target scale, must be >= 1. 259 * @param centerX The screen-relative X coordinate around which to center, 260 * or {@link Float#NaN} to leave unchanged. 261 * @param centerY The screen-relative Y coordinate around which to center, 262 * or {@link Float#NaN} to leave unchanged. 263 */ enableWindowMagnification(int displayId, float scale, float centerX, float centerY)264 void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) { 265 enableWindowMagnification(displayId, scale, centerX, centerY, null); 266 } 267 268 /** 269 * Enables window magnification with specified center and scale on the specified display and 270 * animating the transition. 271 * 272 * @param displayId The logical display id. 273 * @param scale The target scale, must be >= 1. 274 * @param centerX The screen-relative X coordinate around which to center, 275 * or {@link Float#NaN} to leave unchanged. 276 * @param centerY The screen-relative Y coordinate around which to center, 277 * or {@link Float#NaN} to leave unchanged. 278 * @param animationCallback Called when the animation result is valid. 279 */ enableWindowMagnification(int displayId, float scale, float centerX, float centerY, @Nullable MagnificationAnimationCallback animationCallback)280 void enableWindowMagnification(int displayId, float scale, float centerX, float centerY, 281 @Nullable MagnificationAnimationCallback animationCallback) { 282 final boolean enabled; 283 synchronized (mLock) { 284 if (mConnectionWrapper == null) { 285 return; 286 } 287 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 288 if (magnifier == null) { 289 magnifier = createWindowMagnifier(displayId); 290 } 291 enabled = magnifier.enableWindowMagnificationInternal(scale, centerX, centerY, 292 animationCallback); 293 } 294 295 if (enabled) { 296 mCallback.onWindowMagnificationActivationState(displayId, true); 297 } 298 } 299 300 /** 301 * Disables window magnification on the given display. 302 * 303 * @param displayId The logical display id. 304 * @param clear {@true} Clears the state of window magnification. 305 */ disableWindowMagnification(int displayId, boolean clear)306 void disableWindowMagnification(int displayId, boolean clear) { 307 disableWindowMagnification(displayId, clear, null); 308 } 309 310 /** 311 * Disables window magnification on the specified display and animating the transition. 312 * 313 * @param displayId The logical display id. 314 * @param clear {@true} Clears the state of window magnification. 315 * @param animationCallback Called when the animation result is valid. 316 */ disableWindowMagnification(int displayId, boolean clear, MagnificationAnimationCallback animationCallback)317 void disableWindowMagnification(int displayId, boolean clear, 318 MagnificationAnimationCallback animationCallback) { 319 final boolean disabled; 320 synchronized (mLock) { 321 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 322 if (magnifier == null || mConnectionWrapper == null) { 323 return; 324 } 325 disabled = magnifier.disableWindowMagnificationInternal(animationCallback); 326 if (clear) { 327 mWindowMagnifiers.delete(displayId); 328 } 329 } 330 331 if (disabled) { 332 mCallback.onWindowMagnificationActivationState(displayId, false); 333 } 334 } 335 336 /** 337 * Calculates the number of fingers in the window. 338 * 339 * @param displayId The logical display id. 340 * @param motionEvent The motion event 341 * @return the number of fingers in the window. 342 */ pointersInWindow(int displayId, MotionEvent motionEvent)343 int pointersInWindow(int displayId, MotionEvent motionEvent) { 344 synchronized (mLock) { 345 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 346 if (magnifier == null) { 347 return 0; 348 } 349 return magnifier.pointersInWindow(motionEvent); 350 } 351 } 352 353 /** 354 * Indicates whether window magnification is enabled on specified display. 355 * 356 * @param displayId The logical display id. 357 * @return {@code true} if the window magnification is enabled. 358 */ 359 @VisibleForTesting isWindowMagnifierEnabled(int displayId)360 public boolean isWindowMagnifierEnabled(int displayId) { 361 synchronized (mLock) { 362 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 363 if (magnifier == null) { 364 return false; 365 } 366 return magnifier.isEnabled(); 367 } 368 } 369 370 /** 371 * Retrieves a previously persisted magnification scale from the current 372 * user's settings. 373 * 374 * @return the previously persisted magnification scale, or the default 375 * scale if none is available 376 */ getPersistedScale()377 float getPersistedScale() { 378 return Settings.Secure.getFloatForUser(mContext.getContentResolver(), 379 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 380 MIN_SCALE, mUserId); 381 } 382 383 /** 384 * Persists the default display magnification scale to the current user's settings. 385 */ persistScale(int displayId)386 void persistScale(int displayId) { 387 388 float scale = getScale(displayId); 389 if (scale != 1.0f) { 390 BackgroundThread.getHandler().post(() -> { 391 Settings.Secure.putFloatForUser(mContext.getContentResolver(), 392 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale, mUserId); 393 }); 394 } 395 } 396 397 /** 398 * Returns the magnification scale. 399 * 400 * @param displayId The logical display id. 401 * @return the scale 402 */ getScale(int displayId)403 public float getScale(int displayId) { 404 synchronized (mLock) { 405 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 406 if (magnifier == null) { 407 return 1.0f; 408 } 409 return magnifier.getScale(); 410 } 411 } 412 413 /** 414 * Moves window magnification on the specified display with the specified offset. 415 * 416 * @param displayId The logical display id. 417 * @param offsetX the amount in pixels to offset the region in the X direction, in current 418 * screen pixels. 419 * @param offsetY the amount in pixels to offset the region in the Y direction, in current 420 * screen pixels. 421 */ moveWindowMagnification(int displayId, float offsetX, float offsetY)422 void moveWindowMagnification(int displayId, float offsetX, float offsetY) { 423 synchronized (mLock) { 424 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 425 if (magnifier == null) { 426 return; 427 } 428 magnifier.move(offsetX, offsetY); 429 } 430 } 431 432 /** 433 * Requests System UI show magnification mode button UI on the specified display. 434 * 435 * @param displayId The logical display id. 436 * @param magnificationMode the current magnification mode. 437 * @return {@code true} if the event was handled, {@code false} otherwise 438 */ showMagnificationButton(int displayId, int magnificationMode)439 public boolean showMagnificationButton(int displayId, int magnificationMode) { 440 return mConnectionWrapper != null && mConnectionWrapper.showMagnificationButton( 441 displayId, magnificationMode); 442 } 443 444 /** 445 * Requests System UI remove magnification mode button UI on the specified display. 446 * 447 * @param displayId The logical display id. 448 * @return {@code true} if the event was handled, {@code false} otherwise 449 */ removeMagnificationButton(int displayId)450 public boolean removeMagnificationButton(int displayId) { 451 return mConnectionWrapper != null && mConnectionWrapper.removeMagnificationButton( 452 displayId); 453 } 454 455 /** 456 * Returns the screen-relative X coordinate of the center of the magnified bounds. 457 * 458 * @param displayId The logical display id 459 * @return the X coordinate. {@link Float#NaN} if the window magnification is not enabled. 460 */ getCenterX(int displayId)461 float getCenterX(int displayId) { 462 synchronized (mLock) { 463 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 464 if (magnifier == null) { 465 return Float.NaN; 466 } 467 return magnifier.getCenterX(); 468 } 469 } 470 471 /** 472 * Returns the screen-relative Y coordinate of the center of the magnified bounds. 473 * 474 * @param displayId The logical display id 475 * @return the Y coordinate. {@link Float#NaN} if the window magnification is not enabled. 476 */ getCenterY(int displayId)477 float getCenterY(int displayId) { 478 synchronized (mLock) { 479 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 480 if (magnifier == null) { 481 return Float.NaN; 482 } 483 return magnifier.getCenterY(); 484 } 485 } 486 487 /** 488 * Creates the windowMagnifier based on the specified display and stores it. 489 * 490 * @param displayId logical display id. 491 */ 492 @GuardedBy("mLock") createWindowMagnifier(int displayId)493 private WindowMagnifier createWindowMagnifier(int displayId) { 494 final WindowMagnifier magnifier = new WindowMagnifier(displayId, this); 495 mWindowMagnifiers.put(displayId, magnifier); 496 return magnifier; 497 } 498 499 /** 500 * Removes the window magnifier with given id. 501 * 502 * @param displayId The logical display id. 503 */ onDisplayRemoved(int displayId)504 void onDisplayRemoved(int displayId) { 505 disableWindowMagnification(displayId, true); 506 } 507 508 private class ConnectionCallback extends IWindowMagnificationConnectionCallback.Stub implements 509 IBinder.DeathRecipient { 510 private boolean mExpiredDeathRecipient = false; 511 512 @Override onWindowMagnifierBoundsChanged(int displayId, Rect bounds)513 public void onWindowMagnifierBoundsChanged(int displayId, Rect bounds) { 514 synchronized (mLock) { 515 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 516 if (magnifier == null) { 517 magnifier = createWindowMagnifier(displayId); 518 } 519 if (DBG) { 520 Slog.i(TAG, 521 "onWindowMagnifierBoundsChanged -" + displayId + " bounds = " + bounds); 522 } 523 magnifier.setMagnifierLocation(bounds); 524 } 525 } 526 527 @Override onChangeMagnificationMode(int displayId, int magnificationMode)528 public void onChangeMagnificationMode(int displayId, int magnificationMode) 529 throws RemoteException { 530 //TODO: Uses this method to change the magnification mode on non-default display. 531 } 532 533 @Override onSourceBoundsChanged(int displayId, Rect sourceBounds)534 public void onSourceBoundsChanged(int displayId, Rect sourceBounds) { 535 synchronized (mLock) { 536 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); 537 if (magnifier == null) { 538 magnifier = createWindowMagnifier(displayId); 539 } 540 magnifier.onSourceBoundsChanged(sourceBounds); 541 } 542 } 543 544 @Override onPerformScaleAction(int displayId, float scale)545 public void onPerformScaleAction(int displayId, float scale) { 546 mCallback.onPerformScaleAction(displayId, scale); 547 } 548 549 @Override onAccessibilityActionPerformed(int displayId)550 public void onAccessibilityActionPerformed(int displayId) { 551 mCallback.onAccessibilityActionPerformed(displayId); 552 } 553 554 @Override binderDied()555 public void binderDied() { 556 synchronized (mLock) { 557 Slog.w(TAG, "binderDied DeathRecipient :" + mExpiredDeathRecipient); 558 if (mExpiredDeathRecipient) { 559 return; 560 } 561 mConnectionWrapper.unlinkToDeath(this); 562 mConnectionWrapper = null; 563 mConnectionCallback = null; 564 resetWindowMagnifiers(); 565 } 566 } 567 } 568 569 /** 570 * A class manipulates window magnification per display and contains the magnification 571 * information. 572 */ 573 private static class WindowMagnifier { 574 575 private final int mDisplayId; 576 private float mScale = MIN_SCALE; 577 private boolean mEnabled; 578 579 private final WindowMagnificationManager mWindowMagnificationManager; 580 // Records the bounds of window magnification. 581 private final Rect mBounds = new Rect(); 582 // The magnified bounds on the screen. 583 private final Rect mSourceBounds = new Rect(); 584 WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager)585 WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) { 586 mDisplayId = displayId; 587 mWindowMagnificationManager = windowMagnificationManager; 588 } 589 590 @GuardedBy("mLock") enableWindowMagnificationInternal(float scale, float centerX, float centerY, @Nullable MagnificationAnimationCallback animationCallback)591 boolean enableWindowMagnificationInternal(float scale, float centerX, float centerY, 592 @Nullable MagnificationAnimationCallback animationCallback) { 593 if (mEnabled) { 594 return false; 595 } 596 final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); 597 if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale, 598 centerX, centerY, animationCallback)) { 599 mScale = normScale; 600 mEnabled = true; 601 602 return true; 603 } 604 return false; 605 } 606 607 @GuardedBy("mLock") disableWindowMagnificationInternal( @ullable MagnificationAnimationCallback animationResultCallback)608 boolean disableWindowMagnificationInternal( 609 @Nullable MagnificationAnimationCallback animationResultCallback) { 610 if (!mEnabled) { 611 return false; 612 } 613 if (mWindowMagnificationManager.disableWindowMagnificationInternal( 614 mDisplayId, animationResultCallback)) { 615 mEnabled = false; 616 617 return true; 618 } 619 return false; 620 } 621 622 @GuardedBy("mLock") setScale(float scale)623 void setScale(float scale) { 624 if (!mEnabled) { 625 return; 626 } 627 final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); 628 if (Float.compare(mScale, normScale) != 0 629 && mWindowMagnificationManager.setScaleInternal(mDisplayId, scale)) { 630 mScale = normScale; 631 } 632 } 633 634 @GuardedBy("mLock") getScale()635 float getScale() { 636 return mScale; 637 } 638 639 @GuardedBy("mLock") setMagnifierLocation(Rect rect)640 void setMagnifierLocation(Rect rect) { 641 mBounds.set(rect); 642 } 643 644 @GuardedBy("mLock") pointersInWindow(MotionEvent motionEvent)645 int pointersInWindow(MotionEvent motionEvent) { 646 int count = 0; 647 final int pointerCount = motionEvent.getPointerCount(); 648 for (int i = 0; i < pointerCount; i++) { 649 final float x = motionEvent.getX(i); 650 final float y = motionEvent.getY(i); 651 if (mBounds.contains((int) x, (int) y)) { 652 count++; 653 } 654 } 655 return count; 656 } 657 658 @GuardedBy("mLock") isEnabled()659 boolean isEnabled() { 660 return mEnabled; 661 } 662 663 @GuardedBy("mLock") move(float offsetX, float offsetY)664 void move(float offsetX, float offsetY) { 665 mWindowMagnificationManager.moveWindowMagnifierInternal(mDisplayId, offsetX, offsetY); 666 } 667 668 @GuardedBy("mLock") reset()669 void reset() { 670 mEnabled = false; 671 } 672 673 @GuardedBy("mLock") onSourceBoundsChanged(Rect sourceBounds)674 public void onSourceBoundsChanged(Rect sourceBounds) { 675 mSourceBounds.set(sourceBounds); 676 } 677 678 @GuardedBy("mLock") getCenterX()679 float getCenterX() { 680 return mEnabled ? mSourceBounds.exactCenterX() : Float.NaN; 681 } 682 683 @GuardedBy("mLock") getCenterY()684 float getCenterY() { 685 return mEnabled ? mSourceBounds.exactCenterY() : Float.NaN; 686 } 687 } 688 enableWindowMagnificationInternal(int displayId, float scale, float centerX, float centerY, MagnificationAnimationCallback animationCallback)689 private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX, 690 float centerY, MagnificationAnimationCallback animationCallback) { 691 return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification( 692 displayId, scale, centerX, centerY, animationCallback); 693 } 694 setScaleInternal(int displayId, float scale)695 private boolean setScaleInternal(int displayId, float scale) { 696 return mConnectionWrapper != null && mConnectionWrapper.setScale(displayId, scale); 697 } 698 disableWindowMagnificationInternal(int displayId, MagnificationAnimationCallback animationCallback)699 private boolean disableWindowMagnificationInternal(int displayId, 700 MagnificationAnimationCallback animationCallback) { 701 return mConnectionWrapper != null && mConnectionWrapper.disableWindowMagnification( 702 displayId, animationCallback); 703 } 704 moveWindowMagnifierInternal(int displayId, float offsetX, float offsetY)705 private boolean moveWindowMagnifierInternal(int displayId, float offsetX, float offsetY) { 706 return mConnectionWrapper != null && mConnectionWrapper.moveWindowMagnifier( 707 displayId, offsetX, offsetY); 708 } 709 } 710