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