| /* |
| * Copyright (C) 2023 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.inputmethod; |
| |
| import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; |
| import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; |
| |
| import android.app.Activity; |
| import android.app.Dialog; |
| import android.content.Context; |
| import android.graphics.Color; |
| import android.graphics.Point; |
| import android.os.Bundle; |
| import android.view.Display; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewTreeObserver; |
| import android.view.Window; |
| import android.view.WindowInsets; |
| import android.view.WindowManager; |
| import android.widget.Button; |
| import android.widget.FrameLayout; |
| import android.widget.ImageView; |
| |
| import androidx.viewpager.widget.PagerAdapter; |
| import androidx.viewpager.widget.ViewPager; |
| |
| import com.android.settings.R; |
| |
| import com.google.android.material.bottomsheet.BottomSheetBehavior; |
| import com.google.android.material.bottomsheet.BottomSheetDialogFragment; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| |
| public class TrackpadGestureDialogFragment extends BottomSheetDialogFragment { |
| |
| private Context mContext; |
| private LayoutInflater mInflater; |
| private View mViewArrowPrevious; |
| private View mViewArrowNext; |
| private ViewPager mViewPager; |
| private ArrayList<View> mPageList; |
| private ImageView[] mDotIndicators; |
| private View[] mViewPagerItems; |
| private Button mButtonStartSkip; |
| private Button mButtonStartRestart; |
| private Button mButtonEndNext; |
| private Button mButtonEndDone; |
| |
| private static final int DOT_INDICATOR_SIZE = 12; |
| private static final int DOT_INDICATOR_LEFT_PADDING = 6; |
| private static final int DOT_INDICATOR_RIGHT_PADDING = 6; |
| |
| public TrackpadGestureDialogFragment() {} |
| |
| @Override |
| public void onAttach(Context context) { |
| super.onAttach(context); |
| mContext = context; |
| } |
| |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| } |
| |
| @Override |
| public void onStart() { |
| super.onStart(); |
| final Dialog dialog = getDialog(); |
| if (dialog == null) { |
| return; |
| } |
| Window window = dialog.getWindow(); |
| if (window == null) { |
| return; |
| } |
| setLayoutEdgeToEdge(window); |
| final Point size = getScreenSize(); |
| final WindowManager.LayoutParams attributes = window.getAttributes(); |
| attributes.width = (int) (size.x * 0.75); |
| window.setAttributes(attributes); |
| } |
| |
| @Override |
| public void onPause() { |
| super.onPause(); |
| dismiss(); |
| } |
| |
| private static void setLayoutEdgeToEdge(Window window) { |
| View windowDecorView = window.getDecorView(); |
| windowDecorView.setSystemUiVisibility( |
| windowDecorView.getSystemUiVisibility() |
| | View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
| | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); |
| window.setNavigationBarColor(Color.TRANSPARENT); |
| } |
| |
| @Override |
| public Dialog onCreateDialog(final Bundle savedInstanceState) { |
| Dialog dialog = super.onCreateDialog(savedInstanceState); |
| |
| mInflater = mContext.getSystemService(LayoutInflater.class); |
| View contentView = mInflater.inflate(R.layout.trackpad_gesture_preview, null); |
| addViewPager(contentView); |
| dialog.setContentView(contentView); |
| Window gestureDialogWindow = dialog.getWindow(); |
| gestureDialogWindow.setType(TYPE_SYSTEM_DIALOG); |
| |
| // Workaround for solve issue about dialog not full expanded when landscape. |
| FrameLayout bottomSheet = (FrameLayout) |
| dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet); |
| bottomSheet.setBackgroundResource(android.R.color.transparent); |
| BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet); |
| if (!isGestureNavigationEnabled()) { |
| behavior.setState(BottomSheetBehavior.STATE_EXPANDED); |
| } |
| ViewTreeObserver observer = contentView.getViewTreeObserver(); |
| observer.addOnGlobalLayoutListener( |
| new ViewTreeObserver.OnGlobalLayoutListener() { |
| @Override |
| public void onGlobalLayout() { |
| contentView.getViewTreeObserver().removeOnGlobalLayoutListener(this); |
| int contentViewHeight = contentView.getMeasuredHeight(); |
| int navigationBarHeight = getNavigationBarHeight(); |
| behavior.setPeekHeight(contentViewHeight - navigationBarHeight); |
| } |
| }); |
| |
| // The gesture education view shouldn't be draggable." |
| behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { |
| @Override |
| public void onStateChanged(View bottomSheet, int newState) { |
| if (newState == BottomSheetBehavior.STATE_DRAGGING) { |
| if (isGestureNavigationEnabled()) { |
| behavior.setState(BottomSheetBehavior.STATE_COLLAPSED); |
| } else { |
| behavior.setState(BottomSheetBehavior.STATE_EXPANDED); |
| } |
| } |
| } |
| |
| @Override |
| public void onSlide(View bottomSheet, float slideOffset) { |
| // Do nothing. |
| } |
| }); |
| |
| return dialog; |
| } |
| |
| private ArrayList<Integer> getViewPagerResource() { |
| return new ArrayList<Integer>( |
| Arrays.asList( |
| R.layout.gesture_tip1_go_home, |
| R.layout.gesture_tip2_go_back, |
| R.layout.gesture_tip3_recent_apps, |
| R.layout.gesture_tip4_notifications, |
| R.layout.gesture_tip5_switch_apps)); |
| } |
| |
| private void addViewPager(View preview) { |
| mViewPager = preview.findViewById(R.id.viewpager); |
| int viewPagerResourceSize = getViewPagerResource().size(); |
| mViewPagerItems = new View[viewPagerResourceSize]; |
| for (int i = 0; i < viewPagerResourceSize; i++) { |
| mViewPagerItems[i] = |
| mInflater.inflate(getViewPagerResource().get(i), null /* root */); |
| } |
| |
| mPageList = new ArrayList<View>(); |
| for (int i = 0; i < mViewPagerItems.length; i++) { |
| mPageList.add(mViewPagerItems[i]); |
| } |
| |
| mViewPager.setAdapter(new GesturePagerAdapter(mPageList)); |
| |
| mButtonStartRestart = (Button) preview.findViewById(R.id.button_restart); |
| mButtonStartRestart.setOnClickListener(v -> { |
| final int firstPos = mViewPager.getCurrentItem() - mViewPagerItems.length; |
| mViewPager.setCurrentItem(firstPos, true); |
| }); |
| |
| mButtonEndDone = (Button) preview.findViewById(R.id.button_done); |
| mButtonEndDone.setOnClickListener(v -> { |
| dismiss(); |
| }); |
| |
| mButtonStartSkip = (Button) preview.findViewById(R.id.button_skip); |
| mButtonStartSkip.setOnClickListener(v -> { |
| dismiss(); |
| }); |
| |
| mButtonEndNext = (Button) preview.findViewById(R.id.button_next); |
| mButtonEndNext.setOnClickListener(v -> { |
| final int nextPos = mViewPager.getCurrentItem() + 1; |
| mViewPager.setCurrentItem(nextPos, true); |
| }); |
| |
| mViewPager.addOnPageChangeListener(createPageListener()); |
| final ViewGroup viewGroup = (ViewGroup) preview.findViewById(R.id.viewGroup); |
| mDotIndicators = new ImageView[mPageList.size()]; |
| for (int i = 0; i < mPageList.size(); i++) { |
| final ImageView imageView = new ImageView(mContext); |
| final ViewGroup.MarginLayoutParams lp = |
| new ViewGroup.MarginLayoutParams(DOT_INDICATOR_SIZE, DOT_INDICATOR_SIZE); |
| lp.setMargins(DOT_INDICATOR_LEFT_PADDING, 0, DOT_INDICATOR_RIGHT_PADDING, 0); |
| imageView.setLayoutParams(lp); |
| mDotIndicators[i] = imageView; |
| viewGroup.addView(mDotIndicators[i]); |
| } |
| } |
| |
| private static class GesturePagerAdapter extends PagerAdapter { |
| private final ArrayList<View> mPageViewList; |
| |
| GesturePagerAdapter(ArrayList<View> pageViewList) { |
| mPageViewList = pageViewList; |
| } |
| |
| @Override |
| public void destroyItem(ViewGroup container, int position, Object object) { |
| if (mPageViewList.get(position) != null) { |
| container.removeView(mPageViewList.get(position)); |
| } |
| } |
| |
| @Override |
| public Object instantiateItem(ViewGroup container, int position) { |
| container.addView(mPageViewList.get(position)); |
| return mPageViewList.get(position); |
| } |
| |
| @Override |
| public int getCount() { |
| return mPageViewList.size(); |
| } |
| |
| @Override |
| public boolean isViewFromObject(View view, Object object) { |
| return object == view; |
| } |
| } |
| |
| private ViewPager.OnPageChangeListener createPageListener() { |
| return new ViewPager.OnPageChangeListener() { |
| @Override |
| public void onPageScrolled( |
| int position, float positionOffset, int positionOffsetPixels) { |
| if (positionOffset != 0) { |
| for (int i = 0; i < mPageList.size(); i++) { |
| mViewPagerItems[i].setVisibility(View.VISIBLE); |
| } |
| } else { |
| updateIndicator(position); |
| } |
| } |
| |
| @Override |
| public void onPageSelected(int position) {} |
| |
| @Override |
| public void onPageScrollStateChanged(int state) {} |
| }; |
| } |
| |
| private void updateIndicator(int position) { |
| for (int i = 0; i < mPageList.size(); i++) { |
| if (position == i) { |
| mDotIndicators[i].setBackgroundResource( |
| R.drawable.ic_color_page_indicator_focused); |
| mViewPagerItems[i].setVisibility(View.VISIBLE); |
| } else { |
| mDotIndicators[i].setBackgroundResource( |
| R.drawable.ic_color_page_indicator_unfocused); |
| mViewPagerItems[i].setVisibility(View.INVISIBLE); |
| } |
| } |
| |
| if (position >= 0 && position < mViewPagerItems.length - 1) { |
| mButtonStartSkip.setVisibility(View.VISIBLE); |
| mButtonEndNext.setVisibility(View.VISIBLE); |
| mButtonStartRestart.setVisibility(View.GONE); |
| mButtonEndDone.setVisibility(View.GONE); |
| } else { |
| mButtonStartSkip.setVisibility(View.GONE); |
| mButtonEndNext.setVisibility(View.GONE); |
| mButtonStartRestart.setVisibility(View.VISIBLE); |
| mButtonEndDone.setVisibility(View.VISIBLE); |
| } |
| } |
| |
| private Point getScreenSize() { |
| final Point size = new Point(); |
| final Activity activity = (Activity) mContext; |
| final Display display = activity.getWindowManager().getDefaultDisplay(); |
| display.getSize(size); |
| return size; |
| } |
| |
| private int getNavigationBarHeight() { |
| final Activity activity = (Activity) mContext; |
| WindowInsets insets = |
| activity.getWindowManager().getCurrentWindowMetrics().getWindowInsets(); |
| return insets.getInsets(WindowInsets.Type.navigationBars()).bottom; |
| } |
| |
| private boolean isGestureNavigationEnabled() { |
| return NAV_BAR_MODE_GESTURAL == mContext.getResources().getInteger( |
| com.android.internal.R.integer.config_navBarInteractionMode); |
| } |
| } |