Add display preference for scaling / UI Zoom feature
Bug: 22450672 Change-Id: If665576869743fd7d5fc23103260eecaa366e7aa
This commit is contained in:
@@ -6978,4 +6978,22 @@
|
|||||||
|
|
||||||
<!-- Description of feature to change color setting for the display [CHAR LIMIT=NONE] -->
|
<!-- Description of feature to change color setting for the display [CHAR LIMIT=NONE] -->
|
||||||
<string name="picture_color_mode_desc">Use sRGB</string>
|
<string name="picture_color_mode_desc">Use sRGB</string>
|
||||||
|
|
||||||
|
<!-- Title of setting that controls display scale (e.g. density). [CHAR LIMIT=40] -->
|
||||||
|
<string name="force_density_preference_title">Display scale</string>
|
||||||
|
<!-- Keywords for setting that controls display scale (e.g. density). [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="force_density_keywords">display density zoom scale scaling</string>
|
||||||
|
<!-- Description for the display scale that makes interface elements small. [CHAR LIMIT=24] -->
|
||||||
|
<string name="force_density_summary_small">Small</string>
|
||||||
|
<!-- Description for the device's default display scale. [CHAR LIMIT=24] -->
|
||||||
|
<string name="force_density_summary_normal">Normal</string>
|
||||||
|
<!-- Description for the display scale that makes interface elements large. [CHAR LIMIT=24] -->
|
||||||
|
<string name="force_density_summary_large">Large</string>
|
||||||
|
<!-- Description for the display scale that makes interface elements larger. [CHAR LIMIT=24] -->
|
||||||
|
<string name="force_density_summary_very_large">Larger</string>
|
||||||
|
<!-- Description for the display scale that makes interface elements largest. [CHAR LIMIT=24] -->
|
||||||
|
<string name="force_density_summary_extremely_large">Largest</string>
|
||||||
|
<!-- Description for a custom display scale. This shows the requested display
|
||||||
|
density in raw pixels per inch rather than computing a scale amount. [CHAR LIMIT=24] -->
|
||||||
|
<string name="force_density_summary_custom">Custom (<xliff:g id="densityDpi" example="160">%d</xliff:g>)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -99,6 +99,13 @@
|
|||||||
android:entries="@array/entries_font_size"
|
android:entries="@array/entries_font_size"
|
||||||
android:entryValues="@array/entryvalues_font_size" />
|
android:entryValues="@array/entryvalues_font_size" />
|
||||||
|
|
||||||
|
<com.android.settings.DisplayDensityPreference
|
||||||
|
android:key="display_density"
|
||||||
|
android:title="@string/force_density_preference_title"
|
||||||
|
android:summary="%s"
|
||||||
|
settings:keywords="@string/force_density_keywords"
|
||||||
|
android:persistent="false" />
|
||||||
|
|
||||||
<com.android.settings.DropDownPreference
|
<com.android.settings.DropDownPreference
|
||||||
android:key="auto_rotate"
|
android:key="auto_rotate"
|
||||||
android:title="@string/display_auto_rotate_title" />
|
android:title="@string/display_auto_rotate_title" />
|
||||||
|
247
src/com/android/settings/DisplayDensityPreference.java
Normal file
247
src/com/android/settings/DisplayDensityPreference.java
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.settings;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.support.annotation.ArrayRes;
|
||||||
|
import android.support.v7.preference.ListPreference;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.MathUtils;
|
||||||
|
import android.view.Display;
|
||||||
|
import android.view.IWindowManager;
|
||||||
|
import android.view.WindowManagerGlobal;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference for changing the density of the display on which the preference
|
||||||
|
* is visible.
|
||||||
|
*/
|
||||||
|
public class DisplayDensityPreference extends ListPreference {
|
||||||
|
private static final String LOG_TAG = "DisplayDensityPreference";
|
||||||
|
|
||||||
|
/** Minimum increment between density scales. */
|
||||||
|
private static final float MIN_SCALE_INTERVAL = 0.09f;
|
||||||
|
|
||||||
|
/** Minimum density scale. This is available on all devices. */
|
||||||
|
private static final float MIN_SCALE = 0.85f;
|
||||||
|
|
||||||
|
/** Maximum density scale. The actual scale used depends on the device. */
|
||||||
|
private static final float MAX_SCALE = 1.50f;
|
||||||
|
|
||||||
|
/** Sentinel value for "normal" scaling (effectively disabled). */
|
||||||
|
private static final int DENSITY_VALUE_NORMAL = -1;
|
||||||
|
|
||||||
|
/** Summary used for "normal" scale. */
|
||||||
|
private static final int DENSITY_SUMMARY_NORMAL = R.string.force_density_summary_normal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Summaries for scales smaller than "normal" in order of smallest to
|
||||||
|
* largest.
|
||||||
|
*/
|
||||||
|
private static final int[] SMALLER_SUMMARIES = new int[] {
|
||||||
|
R.string.force_density_summary_small
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Summaries for scales larger than "normal" in order of smallest to
|
||||||
|
* largest.
|
||||||
|
*/
|
||||||
|
private static final int[] LARGER_SUMMARIES = new int[] {
|
||||||
|
R.string.force_density_summary_large,
|
||||||
|
R.string.force_density_summary_very_large,
|
||||||
|
R.string.force_density_summary_extremely_large,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum allowed screen dimension, corresponds to resource qualifiers
|
||||||
|
* "small" or "sw320dp". This value must be at least the minimum screen
|
||||||
|
* size required by the CDD so that we meet developer expectations.
|
||||||
|
*/
|
||||||
|
private static final int MIN_DIMENSION_DP = 320;
|
||||||
|
|
||||||
|
/** The ID of the display affected by this preference. */
|
||||||
|
private int mDisplayId = Display.DEFAULT_DISPLAY;
|
||||||
|
|
||||||
|
public DisplayDensityPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
|
||||||
|
if (!prepareList()) {
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean prepareList() {
|
||||||
|
final int initialDensity = getInitialDisplayDensity(mDisplayId);
|
||||||
|
if (initialDensity <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Resources res = getContext().getResources();
|
||||||
|
final DisplayMetrics metrics = res.getDisplayMetrics();
|
||||||
|
final int currentDensity = metrics.densityDpi;
|
||||||
|
int currentDensityIndex = -1;
|
||||||
|
|
||||||
|
// Compute number of "larger" and "smaller" scales for this display.
|
||||||
|
final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
|
||||||
|
final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
|
||||||
|
final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) initialDensity);
|
||||||
|
final float minScale = MIN_SCALE;
|
||||||
|
final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
|
||||||
|
0, LARGER_SUMMARIES.length);
|
||||||
|
final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
|
||||||
|
0, SMALLER_SUMMARIES.length);
|
||||||
|
|
||||||
|
CharSequence[] values = new CharSequence[1 + numSmaller + numLarger];
|
||||||
|
CharSequence[] entries = new CharSequence[values.length];
|
||||||
|
int curIndex = 0;
|
||||||
|
|
||||||
|
if (numSmaller > 0) {
|
||||||
|
final float interval = (1 - minScale) / numSmaller;
|
||||||
|
for (int i = numSmaller - 1; i >= 0; i--) {
|
||||||
|
final int density = (int) (initialDensity * (1 - (i + 1) * interval));
|
||||||
|
if (currentDensity == density) {
|
||||||
|
currentDensityIndex = curIndex;
|
||||||
|
}
|
||||||
|
values[curIndex] = Integer.toString(density);
|
||||||
|
entries[curIndex] = res.getText(SMALLER_SUMMARIES[i]);
|
||||||
|
curIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentDensity == initialDensity) {
|
||||||
|
currentDensityIndex = curIndex;
|
||||||
|
}
|
||||||
|
values[curIndex] = Integer.toString(DENSITY_VALUE_NORMAL);
|
||||||
|
entries[curIndex] = res.getText(DENSITY_SUMMARY_NORMAL);
|
||||||
|
curIndex++;
|
||||||
|
|
||||||
|
if (numLarger > 0) {
|
||||||
|
final float interval = (maxScale - 1) / numLarger;
|
||||||
|
for (int i = 0; i < numLarger; i++) {
|
||||||
|
final int density = (int) (initialDensity * (1 + (i + 1) * interval));
|
||||||
|
if (currentDensity == density) {
|
||||||
|
currentDensityIndex = curIndex;
|
||||||
|
}
|
||||||
|
values[curIndex] = Integer.toString(density);
|
||||||
|
entries[curIndex] = res.getText(LARGER_SUMMARIES[i]);
|
||||||
|
curIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final int displayIndex;
|
||||||
|
if (currentDensityIndex >= 0) {
|
||||||
|
displayIndex = currentDensityIndex;
|
||||||
|
} else {
|
||||||
|
// We don't understand the current density. Must have been set by
|
||||||
|
// someone else. Make room for another entry...
|
||||||
|
values = Arrays.copyOf(values, values.length + 1);
|
||||||
|
values[curIndex] = res.getString(R.string.force_density_summary_custom, currentDensity);
|
||||||
|
|
||||||
|
entries = Arrays.copyOf(entries, values.length + 1);
|
||||||
|
entries[curIndex] = Integer.toString(currentDensity);
|
||||||
|
|
||||||
|
displayIndex = curIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.setEntryValues(values);
|
||||||
|
super.setEntries(entries);
|
||||||
|
|
||||||
|
setValueIndex(displayIndex);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean callChangeListener(Object newValue) {
|
||||||
|
final boolean allowed = super.callChangeListener(newValue);
|
||||||
|
if (allowed) {
|
||||||
|
final int density = Integer.parseInt((String) newValue);
|
||||||
|
setForcedDisplayDensity(mDisplayId, density);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEntries(CharSequence[] entries) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEntries(@ArrayRes int entriesResId) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEntryValues(CharSequence[] entryValues) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEntryValues(@ArrayRes int entryValuesResId) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the initial density for the specified display.
|
||||||
|
*
|
||||||
|
* @param displayId the identifier of the display
|
||||||
|
* @return the initial density of the specified display, or {@code -1} if
|
||||||
|
* the display does not exist or the density could not be obtained
|
||||||
|
*/
|
||||||
|
private static int getInitialDisplayDensity(int displayId) {
|
||||||
|
try {
|
||||||
|
IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
|
||||||
|
return wm.getInitialDisplayDensity(displayId);
|
||||||
|
} catch (RemoteException exc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously applies display density changes to the specified display.
|
||||||
|
*
|
||||||
|
* @param displayId the identifier of the display to modify
|
||||||
|
* @param density the density to force for the specified display, or <= 0
|
||||||
|
* to clear any previously forced density
|
||||||
|
*/
|
||||||
|
private static void setForcedDisplayDensity(final int displayId, final int density) {
|
||||||
|
AsyncTask.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
|
||||||
|
if (density <= 0) {
|
||||||
|
wm.clearForcedDisplayDensity(displayId);
|
||||||
|
} else {
|
||||||
|
wm.setForcedDisplayDensity(displayId, density);
|
||||||
|
}
|
||||||
|
} catch (RemoteException exc) {
|
||||||
|
Log.w(LOG_TAG, "Unable to save forced display density setting");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -76,6 +76,7 @@ public class DisplaySettings extends SettingsPreferenceFragment implements
|
|||||||
private static final String KEY_CAMERA_GESTURE = "camera_gesture";
|
private static final String KEY_CAMERA_GESTURE = "camera_gesture";
|
||||||
private static final String KEY_CAMERA_DOUBLE_TAP_POWER_GESTURE
|
private static final String KEY_CAMERA_DOUBLE_TAP_POWER_GESTURE
|
||||||
= "camera_double_tap_power_gesture";
|
= "camera_double_tap_power_gesture";
|
||||||
|
private static final String KEY_DISPLAY_DENSITY = "display_density";
|
||||||
|
|
||||||
private DropDownPreference mFontSizePref;
|
private DropDownPreference mFontSizePref;
|
||||||
|
|
||||||
@@ -213,6 +214,9 @@ public class DisplaySettings extends SettingsPreferenceFragment implements
|
|||||||
mNightModePreference.setValue(String.valueOf(currentNightMode));
|
mNightModePreference.setValue(String.valueOf(currentNightMode));
|
||||||
mNightModePreference.setOnPreferenceChangeListener(this);
|
mNightModePreference.setOnPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Preference displayDensity = findPreference(KEY_DISPLAY_DENSITY);
|
||||||
|
displayDensity.setOnPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean allowAllRotations(Context context) {
|
private static boolean allowAllRotations(Context context) {
|
||||||
|
Reference in New Issue
Block a user