Add config to disable app tray preview in display size.

Also move some files

Change-Id: I4636fcd81425991acadede0b703e09513c82543c
Fixes: 113374067
Test: robotests
This commit is contained in:
Fan Zhang
2018-09-07 17:06:07 -07:00
parent 6312aa28e3
commit 9aca4cb48c
17 changed files with 194 additions and 99 deletions

View File

@@ -18,7 +18,6 @@ import android.content.res.Resources;
import android.provider.Settings;
import com.android.settings.R;
import com.android.settings.accessibility.ToggleFontSizePreferenceFragment;
import com.android.settings.core.BasePreferenceController;
public class FontSizePreferenceController extends BasePreferenceController {

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2018 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.display;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class FontSizePreferenceFragmentForSetupWizard
extends ToggleFontSizePreferenceFragment {
@Override
public int getMetricsCategory() {
return MetricsEvent.SUW_ACCESSIBILITY_FONT_SIZE;
}
@Override
public void onStop() {
// Log the final choice in value if it's different from the previous value.
if (mCurrentIndex != mInitialIndex) {
mMetricsFeatureProvider.action(getContext(), MetricsEvent.SUW_ACCESSIBILITY_FONT_SIZE,
mCurrentIndex);
}
super.onStop();
}
}

View File

@@ -0,0 +1,221 @@
/*
* Copyright (C) 2018 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.display;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.content.Context;
import android.content.res.Configuration;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.ViewStub.OnInflateListener;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.viewpager.widget.PagerAdapter;
import com.android.settings.support.actionbar.HelpResourceProvider;
/**
* A PagerAdapter used by PreviewSeekBarPreferenceFragment that for showing multiple preview screen
* regarding a single setting and allowing the user to swipe across them.
*/
public class PreviewPagerAdapter extends PagerAdapter {
/** 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 FrameLayout[] mPreviewFrames;
private boolean mIsLayoutRtl;
private Runnable mAnimationEndAction;
private int mAnimationCounter;
private boolean[][] mViewStubInflated;
public PreviewPagerAdapter(Context context, boolean isLayoutRtl,
int[] previewSampleResIds, Configuration[] configurations) {
mIsLayoutRtl = isLayoutRtl;
mPreviewFrames = new FrameLayout[previewSampleResIds.length];
mViewStubInflated = new boolean[previewSampleResIds.length][configurations.length];
for (int i = 0; i < previewSampleResIds.length; ++i) {
int p = mIsLayoutRtl ? previewSampleResIds.length - 1 - i : i;
mPreviewFrames[p] = new FrameLayout(context);
mPreviewFrames[p].setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
for (int j = 0; j < configurations.length; ++j) {
// 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(configurations[j]);
configContext.getTheme().setTo(context.getTheme());
final ViewStub sampleViewStub = new ViewStub(configContext);
sampleViewStub.setLayoutResource(previewSampleResIds[i]);
final int fi = i, fj = j;
sampleViewStub.setOnInflateListener((stub, inflated) -> {
inflated.setVisibility(stub.getVisibility());
mViewStubInflated[fi][fj] = true;
});
mPreviewFrames[p].addView(sampleViewStub);
}
}
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public int getCount() {
return mPreviewFrames.length;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mPreviewFrames[position]);
return mPreviewFrames[position];
}
@Override
public boolean isViewFromObject(View view, Object object) {
return (view == object);
}
boolean isAnimating() {
return mAnimationCounter > 0;
}
void setAnimationEndAction(Runnable action) {
mAnimationEndAction = action;
}
void setPreviewLayer(int newLayerIndex, int currentLayerIndex, int currentFrameIndex,
final boolean animate) {
for (FrameLayout previewFrame : mPreviewFrames) {
if (currentLayerIndex >= 0) {
final View lastLayer = previewFrame.getChildAt(currentLayerIndex);
if (mViewStubInflated[currentFrameIndex][currentLayerIndex]) {
// Explicitly set to INVISIBLE only when the stub has
// already been inflated.
if (previewFrame == mPreviewFrames[currentFrameIndex]) {
setVisibility(lastLayer, View.INVISIBLE, animate);
} else {
setVisibility(lastLayer, View.INVISIBLE, false);
}
}
}
// Set next layer visible, as well as inflate necessary views.
View nextLayer = previewFrame.getChildAt(newLayerIndex);
if (previewFrame == mPreviewFrames[currentFrameIndex]) {
// Inflate immediately if the stub has not yet been inflated.
if (!mViewStubInflated[currentFrameIndex][newLayerIndex]) {
nextLayer = ((ViewStub) nextLayer).inflate();
nextLayer.setAlpha(0.0f);
}
setVisibility(nextLayer, View.VISIBLE, animate);
} else {
setVisibility(nextLayer, View.VISIBLE, false);
}
}
}
private void setVisibility(final View view, final int visibility, boolean animate) {
final float alpha = (visibility == View.VISIBLE ? 1.0f : 0.0f);
if (!animate) {
view.setAlpha(alpha);
view.setVisibility(visibility);
} else {
final Interpolator interpolator = (visibility == View.VISIBLE ? FADE_IN_INTERPOLATOR
: FADE_OUT_INTERPOLATOR);
if (visibility == View.VISIBLE) {
// Fade in animation.
view.animate()
.alpha(alpha)
.setInterpolator(FADE_IN_INTERPOLATOR)
.setDuration(CROSS_FADE_DURATION_MS)
.setListener(new PreviewFrameAnimatorListener())
.withStartAction(new Runnable() {
@Override
public void run() {
view.setVisibility(visibility);
}
});
} else {
// Fade out animation.
view.animate()
.alpha(alpha)
.setInterpolator(FADE_OUT_INTERPOLATOR)
.setDuration(CROSS_FADE_DURATION_MS)
.setListener(new PreviewFrameAnimatorListener())
.withEndAction(new Runnable() {
@Override
public void run() {
view.setVisibility(visibility);
}
});
}
}
}
private void runAnimationEndAction() {
if (mAnimationEndAction != null && !isAnimating()) {
mAnimationEndAction.run();
mAnimationEndAction = null;
}
}
private class PreviewFrameAnimatorListener implements AnimatorListener {
@Override
public void onAnimationStart(Animator animation) {
mAnimationCounter++;
}
@Override
public void onAnimationEnd(Animator animation) {
mAnimationCounter--;
runAnimationEndAction();
}
@Override
public void onAnimationCancel(Animator animation) {
// Empty method.
}
@Override
public void onAnimationRepeat(Animator animation) {
// Empty method.
}
}
}

View File

@@ -0,0 +1,243 @@
/*
* Copyright (C) 2018 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.display;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.widget.DotsPageIndicator;
import com.android.settings.widget.LabeledSeekBar;
/**
* 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;
private ViewPager mPreviewPager;
private PreviewPagerAdapter mPreviewPagerAdapter;
private DotsPageIndicator mPageIndicator;
private TextView mLabel;
private LabeledSeekBar mSeekBar;
private View mLarger;
private View mSmaller;
private class onPreviewSeekBarChangeListener implements OnSeekBarChangeListener {
private boolean mSeekByTouch;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
setPreviewLayer(progress, false);
if (!mSeekByTouch) {
commit();
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mSeekByTouch = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (mPreviewPagerAdapter.isAnimating()) {
mPreviewPagerAdapter.setAnimationEndAction(() -> commit());
} else {
commit();
}
mSeekByTouch = false;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View root = super.onCreateView(inflater, container, savedInstanceState);
final ViewGroup listContainer = root.findViewById(android.R.id.list_container);
listContainer.removeAllViews();
final View content = inflater.inflate(getActivityLayoutResId(), listContainer, false);
listContainer.addView(content);
mLabel = 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);
mSeekBar = content.findViewById(R.id.seek_bar);
mSeekBar.setLabels(mEntries);
mSeekBar.setMax(max);
mSmaller = content.findViewById(R.id.smaller);
mSmaller.setOnClickListener(v -> {
final int progress = mSeekBar.getProgress();
if (progress > 0) {
mSeekBar.setProgress(progress - 1, true);
}
});
mLarger = content.findViewById(R.id.larger);
mLarger.setOnClickListener(v -> {
final int progress = mSeekBar.getProgress();
if (progress < mSeekBar.getMax()) {
mSeekBar.setProgress(progress + 1, true);
}
});
if (mEntries.length == 1) {
// The larger and smaller buttons will be disabled when we call
// setPreviewLayer() later in this method.
mSeekBar.setEnabled(false);
}
final Context context = getContext();
final Configuration origConfig = context.getResources().getConfiguration();
final boolean isLayoutRtl = origConfig.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
Configuration[] configurations = new Configuration[mEntries.length];
for (int i = 0; i < mEntries.length; ++i) {
configurations[i] = createConfig(origConfig, i);
}
final int[] previews = getPreviewSampleResIds();
mPreviewPager = content.findViewById(R.id.preview_pager);
mPreviewPagerAdapter = new PreviewPagerAdapter(context, isLayoutRtl,
previews, configurations);
mPreviewPager.setAdapter(mPreviewPagerAdapter);
mPreviewPager.setCurrentItem(isLayoutRtl ? previews.length - 1 : 0);
mPreviewPager.addOnPageChangeListener(mPreviewPageChangeListener);
mPageIndicator = content.findViewById(R.id.page_indicator);
if (previews.length > 1) {
mPageIndicator.setViewPager(mPreviewPager);
mPageIndicator.setVisibility(View.VISIBLE);
mPageIndicator.setOnPageChangeListener(mPageIndicatorPageChangeListener);
} else {
mPageIndicator.setVisibility(View.GONE);
}
setPreviewLayer(mInitialIndex, false);
return root;
}
@Override
public void onStart() {
super.onStart();
// Set SeekBar listener here to avoid onProgressChanged() is called
// during onRestoreInstanceState().
mSeekBar.setProgress(mCurrentIndex);
mSeekBar.setOnSeekBarChangeListener(new onPreviewSeekBarChangeListener());
}
@Override
public void onStop() {
super.onStop();
mSeekBar.setOnSeekBarChangeListener(null);
}
/** Resource id of the layout for this preference fragment. */
protected abstract int getActivityLayoutResId();
/** Resource id of the layout that defines the contents inside preview screen. */
protected abstract int[] getPreviewSampleResIds();
/**
* Creates new configuration based on the current position of the SeekBar.
*/
protected abstract Configuration createConfig(Configuration origConfig, int index);
/**
* Persists the selected value and sends a configuration change.
*/
protected abstract void commit();
private void setPreviewLayer(int index, boolean animate) {
mLabel.setText(mEntries[index]);
mSmaller.setEnabled(index > 0);
mLarger.setEnabled(index < mEntries.length - 1);
setPagerIndicatorContentDescription(mPreviewPager.getCurrentItem());
mPreviewPagerAdapter.setPreviewLayer(index, mCurrentIndex,
mPreviewPager.getCurrentItem(), animate);
mCurrentIndex = index;
}
private void setPagerIndicatorContentDescription(int position) {
mPageIndicator.setContentDescription(
getString(R.string.preview_page_indicator_content_description,
position + 1, getPreviewSampleResIds().length));
}
private OnPageChangeListener mPreviewPageChangeListener = new OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int state) {
// Do nothing.
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// Do nothing.
}
@Override
public void onPageSelected(int position) {
mPreviewPager.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT);
}
};
private OnPageChangeListener mPageIndicatorPageChangeListener = new OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int state) {
// Do nothing.
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// Do nothing.
}
@Override
public void onPageSelected(int position) {
setPagerIndicatorContentDescription(position);
}
};
}

View File

@@ -18,8 +18,7 @@ package com.android.settings.display;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class ScreenZoomPreferenceFragmentForSetupWizard
extends ScreenZoomSettings {
public class ScreenZoomPreferenceFragmentForSetupWizard extends ScreenZoomSettings {
@Override
public int getMetricsCategory() {

View File

@@ -24,9 +24,9 @@ import android.os.Bundle;
import android.view.Display;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.PreviewSeekBarPreferenceFragment;
import com.android.settings.R;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settingslib.display.DisplayDensityUtils;
import com.android.settingslib.search.SearchIndexable;
@@ -43,17 +43,26 @@ public class ScreenZoomSettings extends PreviewSeekBarPreferenceFragment {
private int mDefaultDensity;
private int[] mValues;
@Override
protected int getActivityLayoutResId() {
return R.layout.screen_zoom_activity;
}
@Override
protected int[] getPreviewSampleResIds() {
return getContext().getResources().getBoolean(
R.bool.config_enable_extra_screen_zoom_preview)
? new int[]{
R.layout.screen_zoom_preview_1,
R.layout.screen_zoom_preview_2,
R.layout.screen_zoom_preview_settings}
: new int[]{R.layout.screen_zoom_preview_1};
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivityLayoutResId = R.layout.screen_zoom_activity;
// This should be replaced once the final preview sample screen is in place.
mPreviewSampleResIds = new int[] {R.layout.screen_zoom_preview_1,
R.layout.screen_zoom_preview_2,
R.layout.screen_zoom_preview_settings};
final DisplayDensityUtils density = new DisplayDensityUtils(getContext());
final int initialIndex = density.getCurrentIndex();
@@ -62,8 +71,8 @@ public class ScreenZoomSettings extends PreviewSeekBarPreferenceFragment {
// connect to the window manager service. Just use the current
// density and don't let the user change anything.
final int densityDpi = getResources().getDisplayMetrics().densityDpi;
mValues = new int[] {densityDpi};
mEntries = new String[] {getString(DisplayDensityUtils.SUMMARY_DEFAULT)};
mValues = new int[]{densityDpi};
mEntries = new String[]{getString(DisplayDensityUtils.SUMMARY_DEFAULT)};
mInitialIndex = 0;
mDefaultDensity = densityDpi;
} else {
@@ -108,7 +117,7 @@ public class ScreenZoomSettings extends PreviewSeekBarPreferenceFragment {
}
/** Index provider used to expose this fragment in search. */
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableRaw> getRawDataToIndex(Context context,

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2018 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.display;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.provider.Settings;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.List;
/**
* Preference fragment used to control font size.
*/
@SearchIndexable
public class ToggleFontSizePreferenceFragment extends PreviewSeekBarPreferenceFragment {
private float[] mValues;
@Override
protected int getActivityLayoutResId() {
return R.layout.font_size_activity;
}
@Override
protected int[] getPreviewSampleResIds() {
return new int[]{R.layout.font_size_preview};
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Resources res = getContext().getResources();
final ContentResolver resolver = getContext().getContentResolver();
// Mark the appropriate item in the preferences list.
mEntries = res.getStringArray(R.array.entries_font_size);
final String[] strEntryValues = res.getStringArray(R.array.entryvalues_font_size);
final float currentScale =
Settings.System.getFloat(resolver, Settings.System.FONT_SCALE, 1.0f);
mInitialIndex = fontSizeValueToIndex(currentScale, strEntryValues);
mValues = new float[strEntryValues.length];
for (int i = 0; i < strEntryValues.length; ++i) {
mValues[i] = Float.parseFloat(strEntryValues[i]);
}
getActivity().setTitle(R.string.title_font_size);
}
@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.
*/
@Override
protected void commit() {
if (getContext() == null) return;
final ContentResolver resolver = getContext().getContentResolver();
Settings.System.putFloat(resolver, Settings.System.FONT_SCALE, mValues[mCurrentIndex]);
}
@Override
public int getHelpResource() {
return R.string.help_url_font_size;
}
@Override
public int getMetricsCategory() {
return MetricsEvent.ACCESSIBILITY_FONT_SIZE;
}
/**
* Utility function that returns the index in a string array with which the represented value is
* the closest to a given float value.
*/
public static int fontSizeValueToIndex(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;
}
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
boolean enabled) {
final ArrayList<SearchIndexableRaw> result = new ArrayList<>();
final SearchIndexableRaw data = new SearchIndexableRaw(context);
data.title = context.getString(R.string.title_font_size);
data.screenTitle = context.getString(R.string.title_font_size);
data.key = "font_size_setting_screen";
data.keywords = context.getString(R.string.keywords_display_font_size);
result.add(data);
return result;
}
};
}