Merge "Adding settings screen for font size. Also factored out common components from screen magnification settings screen."

This commit is contained in:
Noah Wang
2016-01-12 17:04:04 +00:00
committed by Android (Google) Code Review
12 changed files with 483 additions and 177 deletions

View File

@@ -33,6 +33,7 @@ public abstract class InstrumentedFragment extends PreferenceFragment {
public static final int CONFIGURE_NOTIFICATION = UNDECLARED + 3;
public static final int CONFIGURE_WIFI = UNDECLARED + 4;
public static final int DISPLAY_SCREEN_ZOOM = UNDECLARED + 5;
public static final int ACCESSIBILITY_FONT_SIZE = UNDECLARED + 6;
/**
* Declare the view of this category.

View File

@@ -0,0 +1,222 @@
/*
* 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.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
/**
* Preference fragment shows a preview and a seek bar to adjust a specific settings.
*/
public abstract class PreviewSeekBarPreferenceFragment extends SettingsPreferenceFragment {
/** List of entries corresponding the settings being set. */
protected String[] mEntries;
/** Index of the entry corresponding to initial value of the settings. */
protected int mInitialIndex;
/** Index of the entry corresponding to current value of the settings. */
protected int mCurrentIndex;
/** Resource id of the layout for this preference fragment. */
protected int mActivityLayoutResId;
/** Resource id of the layout that defines the contents instide preview screen. */
protected int mPreviewSampleResId;
/** Duration to use when cross-fading between previews. */
private static final long CROSS_FADE_DURATION_MS = 400;
/** Interpolator to use when cross-fading between previews. */
private static final Interpolator FADE_IN_INTERPOLATOR = new DecelerateInterpolator();
/** Interpolator to use when cross-fading between previews. */
private static final Interpolator FADE_OUT_INTERPOLATOR = new AccelerateInterpolator();
private ViewGroup mPreviewFrame;
private TextView mLabel;
private View mLarger;
private View mSmaller;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View root = super.onCreateView(inflater, container, savedInstanceState);
final ViewGroup listContainer = (ViewGroup) root.findViewById(android.R.id.list_container);
listContainer.removeAllViews();
final View content = inflater.inflate(mActivityLayoutResId, listContainer, false);
listContainer.addView(content);
mLabel = (TextView) content.findViewById(R.id.current_label);
// The maximum SeekBar value always needs to be non-zero. If there's
// only one available value, we'll handle this by disabling the
// seek bar.
final int max = Math.max(1, mEntries.length - 1);
final SeekBar seekBar = (SeekBar) content.findViewById(R.id.seek_bar);
seekBar.setMax(max);
seekBar.setProgress(mInitialIndex);
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
setPreviewLayer(progress, true);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
mSmaller = content.findViewById(R.id.smaller);
mSmaller.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
final int progress = seekBar.getProgress();
if (progress > 0) {
seekBar.setProgress(progress - 1, true);
}
}
});
mLarger = content.findViewById(R.id.larger);
mLarger.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
final int progress = seekBar.getProgress();
if (progress < seekBar.getMax()) {
seekBar.setProgress(progress + 1, true);
}
}
});
if (mEntries.length == 1) {
// The larger and smaller buttons will be disabled when we call
// setPreviewLayer() later in this method.
seekBar.setEnabled(false);
}
mPreviewFrame = (FrameLayout) content.findViewById(R.id.preview_frame);
// Populate the sample layouts.
final Context context = getContext();
final Configuration origConfig = context.getResources().getConfiguration();
for (int i = 0; i < mEntries.length; ++i) {
final Configuration config = createConfig(origConfig, i);
// Create a new configuration for the specified value. It won't
// have any theme set, so manually apply the current theme.
final Context configContext = context.createConfigurationContext(config);
configContext.setTheme(context.getThemeResId());
final LayoutInflater configInflater = LayoutInflater.from(configContext);
final View sampleView = configInflater.inflate(mPreviewSampleResId, mPreviewFrame, false);
sampleView.setAlpha(0);
sampleView.setVisibility(View.INVISIBLE);
mPreviewFrame.addView(sampleView);
}
setPreviewLayer(mInitialIndex, false);
return root;
}
@Override
public void onDetach() {
super.onDetach();
// This will commit the change SLIGHTLY after the activity has
// finished, which could be considered a feature or a bug...
commit();
}
/**
* Creates new configuration based on the current position of the SeekBar.
*/
protected abstract Configuration createConfig(Configuration origConfig, int index);
private void setPreviewLayer(int index, boolean animate) {
mLabel.setText(mEntries[index]);
if (mCurrentIndex >= 0) {
final View lastLayer = mPreviewFrame.getChildAt(mCurrentIndex);
if (animate) {
lastLayer.animate()
.alpha(0)
.setInterpolator(FADE_OUT_INTERPOLATOR)
.setDuration(CROSS_FADE_DURATION_MS)
.withEndAction(new Runnable() {
@Override
public void run() {
lastLayer.setVisibility(View.INVISIBLE);
}
});
} else {
lastLayer.setAlpha(0);
lastLayer.setVisibility(View.INVISIBLE);
}
}
final View nextLayer = mPreviewFrame.getChildAt(index);
if (animate) {
nextLayer.animate()
.alpha(1)
.setInterpolator(FADE_IN_INTERPOLATOR)
.setDuration(CROSS_FADE_DURATION_MS)
.withStartAction(new Runnable() {
@Override
public void run() {
nextLayer.setVisibility(View.VISIBLE);
}
});
} else {
nextLayer.setVisibility(View.VISIBLE);
nextLayer.setAlpha(1);
}
mSmaller.setEnabled(index > 0);
mLarger.setEnabled(index < mEntries.length - 1);
mCurrentIndex = index;
}
/**
* Persists the selected value and sends a configuration change.
*/
protected abstract void commit();
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.settings.display;
package com.android.settings;
import android.annotation.Nullable;
import android.content.Context;

View File

@@ -0,0 +1,97 @@
/*
* 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.accessibility;
import com.android.settings.InstrumentedFragment;
import com.android.settings.R;
import com.android.settings.PreviewSeekBarPreferenceFragment;
import android.annotation.Nullable;
import android.app.ActivityManagerNative;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
/**
* Preference fragment used to control font size.
*/
public class ToggleFontSizePreferenceFragment extends PreviewSeekBarPreferenceFragment {
private static final String LOG_TAG = "ToggleFontSizePreferenceFragment";
private float[] mValues;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivityLayoutResId = R.layout.font_size_activity;
mPreviewSampleResId = R.layout.font_size_preview;
Resources res = getContext().getResources();
// Mark the appropriate item in the preferences list.
final Configuration origConfig = res.getConfiguration();
mEntries = res.getStringArray(R.array.entries_font_size);
final String[] strEntryValues = res.getStringArray(R.array.entryvalues_font_size);
mInitialIndex = floatToIndex(origConfig.fontScale, strEntryValues);
mValues = new float[strEntryValues.length];
for (int i = 0; i < strEntryValues.length; ++i) {
mValues[i] = Float.parseFloat(strEntryValues[i]);
}
}
@Override
protected Configuration createConfig(Configuration origConfig, int index) {
// Populate the sample layouts.
final Configuration config = new Configuration(origConfig);
config.fontScale = mValues[index];
return config;
}
/**
* Persists the selected font size and sends a configuration change.
*/
@Override
protected void commit() {
Configuration config = getContext().getResources().getConfiguration();
config.fontScale = mValues[mCurrentIndex];
try {
ActivityManagerNative.getDefault().updatePersistentConfiguration(config);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Unable to save font size setting");
}
}
@Override
protected int getMetricsCategory() {
return InstrumentedFragment.ACCESSIBILITY_FONT_SIZE;
}
private int floatToIndex(float val, String[] indices) {
float lastVal = Float.parseFloat(indices[0]);
for (int i=1; i<indices.length; i++) {
float thisVal = Float.parseFloat(indices[i]);
if (val < (lastVal + (thisVal-lastVal)*.5f)) {
return i-1;
}
lastVal = thisVal;
}
return indices.length-1;
}
}

View File

@@ -18,7 +18,7 @@ package com.android.settings.display;
import com.android.settings.InstrumentedFragment;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.PreviewSeekBarPreferenceFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
@@ -29,17 +29,6 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
@@ -47,32 +36,17 @@ import java.util.List;
/**
* Preference fragment used to control screen zoom.
*/
public class ScreenZoomSettings extends SettingsPreferenceFragment implements Indexable {
/** Duration to use when cross-fading between previews. */
private static final long CROSS_FADE_DURATION_MS = 400;
public class ScreenZoomSettings extends PreviewSeekBarPreferenceFragment implements Indexable {
/** Interpolator to use when cross-fading between previews. */
private static final Interpolator FADE_IN_INTERPOLATOR = new DecelerateInterpolator();
/** Interpolator to use when cross-fading between previews. */
private static final Interpolator FADE_OUT_INTERPOLATOR = new AccelerateInterpolator();
private ViewGroup mPreviewFrame;
private TextView mLabel;
private View mLarger;
private View mSmaller;
private String[] mEntries;
private int[] mValues;
private int mNormalDensity;
private int mInitialIndex;
private int mCurrentIndex;
private int[] mValues;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivityLayoutResId = R.layout.screen_zoom_activity;
mPreviewSampleResId = R.layout.screen_zoom_preview;
final DisplayDensityUtils density = new DisplayDensityUtils(getContext());
final int initialIndex = density.getCurrentIndex();
@@ -94,152 +68,18 @@ public class ScreenZoomSettings extends SettingsPreferenceFragment implements In
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View root = super.onCreateView(inflater, container, savedInstanceState);
final ViewGroup list_container = (ViewGroup) root.findViewById(android.R.id.list_container);
list_container.removeAllViews();
final View content = inflater.inflate(R.layout.screen_zoom_activity, list_container, false);
list_container.addView(content);
mLabel = (TextView) content.findViewById(R.id.current_density);
// The maximum SeekBar value always needs to be non-zero. If there's
// only one available zoom level, we'll handle this by disabling the
// seek bar.
final int max = Math.max(1, mValues.length - 1);
final SeekBar seekBar = (SeekBar) content.findViewById(R.id.seek_bar);
seekBar.setMax(max);
seekBar.setProgress(mInitialIndex);
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
setPreviewLayer(progress, true);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
mSmaller = content.findViewById(R.id.smaller);
mSmaller.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
final int progress = seekBar.getProgress();
if (progress > 0) {
seekBar.setProgress(progress - 1, true);
}
}
});
mLarger = content.findViewById(R.id.larger);
mLarger.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
final int progress = seekBar.getProgress();
if (progress < seekBar.getMax()) {
seekBar.setProgress(progress + 1, true);
}
}
});
if (mValues.length == 1) {
// The larger and smaller buttons will be disabled when we call
// setPreviewLayer() later in this method.
seekBar.setEnabled(false);
}
mPreviewFrame = (FrameLayout) content.findViewById(R.id.preview_frame);
protected Configuration createConfig(Configuration origConfig, int index) {
// Populate the sample layouts.
final Context context = getContext();
final Configuration origConfig = context.getResources().getConfiguration();
for (int mValue : mValues) {
final Configuration config = new Configuration(origConfig);
config.densityDpi = mValue;
// Create a new configuration for the specified density. It won't
// have any theme set, so manually apply the current theme.
final Context configContext = context.createConfigurationContext(config);
configContext.setTheme(context.getThemeResId());
final LayoutInflater configInflater = LayoutInflater.from(configContext);
final View sampleView = configInflater.inflate(
R.layout.screen_zoom_preview, mPreviewFrame, false);
sampleView.setAlpha(0);
sampleView.setVisibility(View.INVISIBLE);
mPreviewFrame.addView(sampleView);
}
setPreviewLayer(mInitialIndex, false);
return root;
}
@Override
public void onDetach() {
super.onDetach();
// This will adjust the density SLIGHTLY after the activity has
// finished, which could be considered a feature or a bug...
commit();
}
private void setPreviewLayer(int index, boolean animate) {
mLabel.setText(mEntries[index]);
if (mCurrentIndex >= 0) {
final View lastLayer = mPreviewFrame.getChildAt(mCurrentIndex);
if (animate) {
lastLayer.animate()
.alpha(0)
.setInterpolator(FADE_OUT_INTERPOLATOR)
.setDuration(CROSS_FADE_DURATION_MS)
.withEndAction(new Runnable() {
@Override
public void run() {
lastLayer.setVisibility(View.INVISIBLE);
}
});
} else {
lastLayer.setAlpha(0);
lastLayer.setVisibility(View.INVISIBLE);
}
}
final View nextLayer = mPreviewFrame.getChildAt(index);
if (animate) {
nextLayer.animate()
.alpha(1)
.setInterpolator(FADE_IN_INTERPOLATOR)
.setDuration(CROSS_FADE_DURATION_MS)
.withStartAction(new Runnable() {
@Override
public void run() {
nextLayer.setVisibility(View.VISIBLE);
}
});
} else {
nextLayer.setVisibility(View.VISIBLE);
nextLayer.setAlpha(1);
}
mSmaller.setEnabled(index > 0);
mLarger.setEnabled(index < mEntries.length - 1);
mCurrentIndex = index;
final Configuration config = new Configuration(origConfig);
config.densityDpi = mValues[index];
return config;
}
/**
* Persists the selected density and sends a configuration change.
*/
private void commit() {
@Override
protected void commit() {
final int densityDpi = mValues[mCurrentIndex];
if (densityDpi == mNormalDensity) {
DisplayDensityUtils.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);