1 /* 2 * Copyright (C) 2021 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.content.Context; 20 import android.os.UserHandle; 21 import android.provider.Settings; 22 import android.util.MathUtils; 23 import android.util.SparseArray; 24 import android.view.Display; 25 26 import com.android.internal.annotations.GuardedBy; 27 import com.android.internal.annotations.VisibleForTesting; 28 import com.android.internal.os.BackgroundThread; 29 30 /** 31 * Supplies setter/getter of the magnification scale for the given display. Only the value of the 32 * default play is persisted. It also constraints the range of applied magnification scale between 33 * [MIN_SCALE, MAX_SCALE] which is consistent with the range provided by 34 * {@code AccessibilityService.MagnificationController#setScale()}. 35 */ 36 public class MagnificationScaleProvider { 37 38 @VisibleForTesting 39 protected static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f; 40 public static final float MIN_SCALE = 1.0f; 41 public static final float MAX_SCALE = 8.0f; 42 43 private final Context mContext; 44 // Stores the scale for non-default displays. 45 @GuardedBy("mLock") 46 private final SparseArray<SparseArray<Float>> mUsersScales = new SparseArray(); 47 private int mCurrentUserId = UserHandle.USER_SYSTEM; 48 private final Object mLock = new Object(); 49 MagnificationScaleProvider(Context context)50 public MagnificationScaleProvider(Context context) { 51 mContext = context; 52 } 53 54 /** 55 * Stores the user settings scale associated to the given display. Only the scale of the 56 * default display is persistent. 57 * 58 * @param scale the magnification scale 59 * @param displayId the id of the display 60 */ putScale(float scale, int displayId)61 void putScale(float scale, int displayId) { 62 if (displayId == Display.DEFAULT_DISPLAY) { 63 BackgroundThread.getHandler().post( 64 () -> Settings.Secure.putFloatForUser(mContext.getContentResolver(), 65 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale, 66 mCurrentUserId)); 67 } else { 68 synchronized (mLock) { 69 getScalesWithCurrentUser().put(displayId, scale); 70 } 71 } 72 } 73 74 /** 75 * Gets the user settings scale with the given display. 76 * 77 * @param displayId the id of the display 78 * @return the magnification scale. 79 */ getScale(int displayId)80 float getScale(int displayId) { 81 if (displayId == Display.DEFAULT_DISPLAY) { 82 return Settings.Secure.getFloatForUser(mContext.getContentResolver(), 83 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 84 DEFAULT_MAGNIFICATION_SCALE, mCurrentUserId); 85 } else { 86 synchronized (mLock) { 87 return getScalesWithCurrentUser().get(displayId, DEFAULT_MAGNIFICATION_SCALE); 88 } 89 } 90 } 91 92 93 @GuardedBy("mLock") getScalesWithCurrentUser()94 private SparseArray<Float> getScalesWithCurrentUser() { 95 SparseArray<Float> scales = mUsersScales.get(mCurrentUserId); 96 if (scales == null) { 97 scales = new SparseArray<>(); 98 mUsersScales.put(mCurrentUserId, scales); 99 } 100 101 return scales; 102 } 103 onUserChanged(int userId)104 void onUserChanged(int userId) { 105 synchronized (mLock) { 106 mCurrentUserId = userId; 107 } 108 } 109 onUserRemoved(int userId)110 void onUserRemoved(int userId) { 111 synchronized (mLock) { 112 mUsersScales.remove(userId); 113 } 114 } 115 onDisplayRemoved(int displayId)116 void onDisplayRemoved(int displayId) { 117 synchronized (mLock) { 118 final int userCounts = mUsersScales.size(); 119 for (int i = userCounts - 1; i >= 0; i--) { 120 mUsersScales.get(i).remove(displayId); 121 } 122 } 123 } 124 125 @Override toString()126 public String toString() { 127 synchronized (mLock) { 128 return "MagnificationScaleProvider{" 129 + "mCurrentUserId=" + mCurrentUserId 130 + "Scale on the default display=" + getScale(Display.DEFAULT_DISPLAY) 131 + "Scales on non-default displays=" + getScalesWithCurrentUser() 132 + '}'; 133 } 134 } 135 constrainScale(float scale)136 static float constrainScale(float scale) { 137 return MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); 138 } 139 } 140