• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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