blob: 8e1aa38be9e87c98b70d09ba997d02fca9f5f6ce [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.accessibility.magnification;
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.MathUtils;
import android.util.SparseArray;
import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
/**
* Supplies setter/getter of the magnification scale for the given display. Only the value of the
* default play is persisted. It also constraints the range of applied magnification scale between
* [MIN_SCALE, MAX_SCALE] which is consistent with the range provided by
* {@code AccessibilityService.MagnificationController#setScale()}.
*/
public class MagnificationScaleProvider {
@VisibleForTesting
protected static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
public static final float MIN_SCALE = 1.0f;
public static final float MAX_SCALE = 8.0f;
private final Context mContext;
// Stores the scale for non-default displays.
@GuardedBy("mLock")
private final SparseArray<SparseArray<Float>> mUsersScales = new SparseArray();
private int mCurrentUserId = UserHandle.USER_SYSTEM;
private final Object mLock = new Object();
public MagnificationScaleProvider(Context context) {
mContext = context;
}
/**
* Stores the user settings scale associated to the given display. Only the scale of the
* default display is persistent.
*
* @param scale the magnification scale
* @param displayId the id of the display
*/
void putScale(float scale, int displayId) {
if (displayId == Display.DEFAULT_DISPLAY) {
BackgroundThread.getHandler().post(
() -> Settings.Secure.putFloatForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale,
mCurrentUserId));
} else {
synchronized (mLock) {
getScalesWithCurrentUser().put(displayId, scale);
}
}
}
/**
* Gets the user settings scale with the given display.
*
* @param displayId the id of the display
* @return the magnification scale.
*/
float getScale(int displayId) {
if (displayId == Display.DEFAULT_DISPLAY) {
return Settings.Secure.getFloatForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
DEFAULT_MAGNIFICATION_SCALE, mCurrentUserId);
} else {
synchronized (mLock) {
return getScalesWithCurrentUser().get(displayId, DEFAULT_MAGNIFICATION_SCALE);
}
}
}
@GuardedBy("mLock")
private SparseArray<Float> getScalesWithCurrentUser() {
SparseArray<Float> scales = mUsersScales.get(mCurrentUserId);
if (scales == null) {
scales = new SparseArray<>();
mUsersScales.put(mCurrentUserId, scales);
}
return scales;
}
void onUserChanged(int userId) {
synchronized (mLock) {
mCurrentUserId = userId;
}
}
void onUserRemoved(int userId) {
synchronized (mLock) {
mUsersScales.remove(userId);
}
}
void onDisplayRemoved(int displayId) {
synchronized (mLock) {
final int userCounts = mUsersScales.size();
for (int i = userCounts - 1; i >= 0; i--) {
mUsersScales.get(i).remove(displayId);
}
}
}
@Override
public String toString() {
synchronized (mLock) {
return "MagnificationScaleProvider{"
+ "mCurrentUserId=" + mCurrentUserId
+ "Scale on the default display=" + getScale(Display.DEFAULT_DISPLAY)
+ "Scales on non-default displays=" + getScalesWithCurrentUser()
+ '}';
}
}
static float constrainScale(float scale) {
return MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
}
}