| /* | |
| * Copyright (C) 2022 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 android.content.Context; | |
| import android.os.Bundle; | |
| import android.os.Parcelable; | |
| import android.util.AttributeSet; | |
| import android.view.View; | |
| import android.widget.FrameLayout; | |
| import android.widget.ImageButton; | |
| import android.widget.LinearLayout; | |
| import androidx.preference.Preference; | |
| import androidx.preference.PreferenceViewHolder; | |
| import androidx.viewpager.widget.ViewPager; | |
| import com.android.internal.annotations.VisibleForTesting; | |
| import com.android.internal.util.Preconditions; | |
| import com.android.settings.R; | |
| import com.android.settings.display.PreviewPagerAdapter; | |
| import com.android.settings.widget.DotsPageIndicator; | |
| /** | |
| * A {@link Preference} that could show the preview related to the text and reading options. | |
| */ | |
| public class TextReadingPreviewPreference extends Preference { | |
| private static final String KEY_LAST_INDEX = "last_preview_index"; | |
| private int mCurrentItem; | |
| private int mLastLayerIndex; | |
| private PreviewPagerAdapter mPreviewAdapter; | |
| private int mLayoutMinHorizontalPadding = 0; | |
| private int mBackgroundMinHorizontalPadding = 0; | |
| private final ViewPager.OnPageChangeListener mPageChangeListener = | |
| new ViewPager.OnPageChangeListener() { | |
| @Override | |
| public void onPageScrolled(int i, float v, int i1) { | |
| // Do nothing | |
| } | |
| @Override | |
| public void onPageSelected(int i) { | |
| mCurrentItem = i; | |
| } | |
| @Override | |
| public void onPageScrollStateChanged(int i) { | |
| // Do nothing | |
| } | |
| }; | |
| TextReadingPreviewPreference(Context context) { | |
| super(context); | |
| init(); | |
| } | |
| public TextReadingPreviewPreference(Context context, AttributeSet attrs) { | |
| super(context, attrs); | |
| init(); | |
| } | |
| TextReadingPreviewPreference(Context context, AttributeSet attrs, int defStyleAttr) { | |
| super(context, attrs, defStyleAttr); | |
| init(); | |
| } | |
| TextReadingPreviewPreference(Context context, AttributeSet attrs, int defStyleAttr, | |
| int defStyleRes) { | |
| super(context, attrs, defStyleAttr, defStyleRes); | |
| init(); | |
| } | |
| @Override | |
| public void onBindViewHolder(PreferenceViewHolder holder) { | |
| super.onBindViewHolder(holder); | |
| FrameLayout previewLayout = (FrameLayout) holder.itemView; | |
| LinearLayout backgroundView = previewLayout.findViewById(R.id.preview_background); | |
| adjustPaddings(previewLayout, backgroundView); | |
| final ViewPager viewPager = (ViewPager) holder.findViewById(R.id.preview_pager); | |
| viewPager.addOnPageChangeListener(mPageChangeListener); | |
| final DotsPageIndicator pageIndicator = | |
| (DotsPageIndicator) holder.findViewById(R.id.page_indicator); | |
| updateAdapterIfNeeded(viewPager, pageIndicator, mPreviewAdapter); | |
| updatePagerAndIndicator(viewPager, pageIndicator); | |
| viewPager.setClipToOutline(true); | |
| int layoutDirection = | |
| getContext().getResources().getConfiguration().getLayoutDirection(); | |
| int previousId = (layoutDirection == View.LAYOUT_DIRECTION_RTL) | |
| ? R.id.preview_right_button : R.id.preview_left_button; | |
| int nextId = (layoutDirection == View.LAYOUT_DIRECTION_RTL) | |
| ? R.id.preview_left_button : R.id.preview_right_button; | |
| final ImageButton previousButton = previewLayout.findViewById(previousId); | |
| final ImageButton nextButton = previewLayout.findViewById(nextId); | |
| // These call ViewPager#setCurrentItem directly | |
| // because that doesn't force a refresh through notifyChanged(). | |
| // We found this avoids a crash in SUW (See b/386906497). | |
| previousButton.setOnClickListener((view) -> | |
| viewPager.setCurrentItem(getCurrentItem() - 1)); | |
| previousButton.setContentDescription(getContext().getString( | |
| R.string.preview_pager_previous_button)); | |
| nextButton.setOnClickListener((view) -> | |
| viewPager.setCurrentItem(getCurrentItem() + 1)); | |
| nextButton.setContentDescription(getContext().getString( | |
| R.string.preview_pager_next_button)); | |
| } | |
| @Override | |
| protected Parcelable onSaveInstanceState() { | |
| Bundle state = new Bundle(); | |
| state.putParcelable(null, super.onSaveInstanceState()); | |
| state.putInt(KEY_LAST_INDEX, getCurrentItem()); | |
| return state; | |
| } | |
| @Override | |
| protected void onRestoreInstanceState(Parcelable state) { | |
| Bundle bundle = (Bundle) state; | |
| super.onRestoreInstanceState(bundle.getParcelable(null)); | |
| setCurrentItem(bundle.getInt(KEY_LAST_INDEX)); | |
| } | |
| /** | |
| * Set the minimum preview layout horizontal inner padding. | |
| */ | |
| void setLayoutMinHorizontalPadding(int layoutMinHorizontalPadding) { | |
| mLayoutMinHorizontalPadding = layoutMinHorizontalPadding; | |
| } | |
| /** | |
| * Set the minimum preview background view horizontal inner padding. | |
| */ | |
| void setBackgroundMinHorizontalPadding(int backgroundMinHorizontalPadding) { | |
| mBackgroundMinHorizontalPadding = backgroundMinHorizontalPadding; | |
| } | |
| @VisibleForTesting | |
| void adjustPaddings(FrameLayout previewLayout, LinearLayout backgroundView) { | |
| previewLayout.setPadding( | |
| Math.max(previewLayout.getPaddingStart(), mLayoutMinHorizontalPadding), | |
| previewLayout.getPaddingTop(), | |
| Math.max(previewLayout.getPaddingEnd(), mLayoutMinHorizontalPadding), | |
| previewLayout.getPaddingBottom() | |
| ); | |
| backgroundView.setPadding( | |
| Math.max(backgroundView.getPaddingStart(), mBackgroundMinHorizontalPadding), | |
| backgroundView.getPaddingTop(), | |
| Math.max(backgroundView.getPaddingEnd(), mBackgroundMinHorizontalPadding), | |
| backgroundView.getPaddingBottom() | |
| ); | |
| } | |
| void setPreviewAdapter(PreviewPagerAdapter previewAdapter) { | |
| if (previewAdapter != mPreviewAdapter) { | |
| mPreviewAdapter = previewAdapter; | |
| notifyChanged(); | |
| } | |
| } | |
| void setCurrentItem(int currentItem) { | |
| Preconditions.checkNotNull(mPreviewAdapter, | |
| "Preview adapter is null, you should init the preview adapter first"); | |
| if (currentItem != mCurrentItem) { | |
| mCurrentItem = currentItem; | |
| notifyChanged(); | |
| } | |
| } | |
| void setLastLayerIndex(int lastLayerIndex) { | |
| mLastLayerIndex = lastLayerIndex; | |
| } | |
| int getCurrentItem() { | |
| return mCurrentItem; | |
| } | |
| private void updateAdapterIfNeeded(ViewPager viewPager, DotsPageIndicator pageIndicator, | |
| PreviewPagerAdapter previewAdapter) { | |
| if (viewPager.getAdapter() == previewAdapter) { | |
| return; | |
| } | |
| viewPager.setAdapter(previewAdapter); | |
| if (previewAdapter != null) { | |
| pageIndicator.setViewPager(viewPager); | |
| } else { | |
| mCurrentItem = 0; | |
| } | |
| } | |
| private void updatePagerAndIndicator(ViewPager viewPager, DotsPageIndicator pageIndicator) { | |
| if (viewPager.getAdapter() == null) { | |
| return; | |
| } | |
| if (viewPager.getCurrentItem() != mCurrentItem) { | |
| viewPager.setCurrentItem(mCurrentItem); | |
| } | |
| pageIndicator.setVisibility( | |
| viewPager.getAdapter().getCount() > 1 ? View.VISIBLE : View.GONE); | |
| } | |
| private void init() { | |
| // set up the minimum horizontal paddings | |
| setLayoutMinHorizontalPadding(getContext().getResources().getDimensionPixelSize( | |
| R.dimen.text_reading_preview_layout_padding_horizontal_min)); | |
| setBackgroundMinHorizontalPadding(getContext().getResources().getDimensionPixelSize( | |
| R.dimen.text_reading_preview_background_padding_horizontal_min)); | |
| setLayoutResource(R.layout.accessibility_text_reading_preview); | |
| } | |
| void notifyPreviewPagerChanged(int pagerIndex) { | |
| Preconditions.checkNotNull(mPreviewAdapter, | |
| "Preview adapter is null, you should init the preview adapter first"); | |
| if (pagerIndex != mLastLayerIndex) { | |
| mPreviewAdapter.setPreviewLayer(pagerIndex, mLastLayerIndex, getCurrentItem(), | |
| /* animate= */ false); | |
| } | |
| mLastLayerIndex = pagerIndex; | |
| } | |
| } |