Change I930e9fc85e09e03da3513e5f8443077fa8ea91b0 triggered some NullAway warnings that are unrelated to the change, but some are trivial to fix, for example by replacing member variables with local ones. At the same time, add some `@NonNull` annotations to overriding methods on Android Studio's recommendation. Test: check touchpad gesture tutorial and pointer speed settings work Test: $ atest SettingsRoboTests:com.android.settings.inputmethod Bug: 245989146 Flag: EXEMPT refactor Change-Id: I717eb2a2d68a46dce8ebaa95bef1183d09380f51
327 lines
12 KiB
Java
327 lines
12 KiB
Java
/*
|
|
* 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.annotation.NonNull;
|
|
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 TouchpadGestureDialogFragment extends BottomSheetDialogFragment {
|
|
|
|
private Context mContext;
|
|
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;
|
|
|
|
@Override
|
|
public void onAttach(@NonNull 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);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
|
Dialog dialog = super.onCreateDialog(savedInstanceState);
|
|
|
|
LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
|
|
View contentView = inflater.inflate(R.layout.touchpad_gesture_preview, null);
|
|
addViewPager(contentView, inflater);
|
|
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(@NonNull 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(@NonNull 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, LayoutInflater inflater) {
|
|
ViewPager viewPager = preview.findViewById(R.id.viewpager);
|
|
int viewPagerResourceSize = getViewPagerResource().size();
|
|
mViewPagerItems = new View[viewPagerResourceSize];
|
|
for (int i = 0; i < viewPagerResourceSize; i++) {
|
|
mViewPagerItems[i] = inflater.inflate(getViewPagerResource().get(i), null /* root */);
|
|
}
|
|
|
|
mPageList = new ArrayList<View>();
|
|
for (int i = 0; i < mViewPagerItems.length; i++) {
|
|
mPageList.add(mViewPagerItems[i]);
|
|
}
|
|
|
|
viewPager.setAdapter(new GesturePagerAdapter(mPageList));
|
|
|
|
mButtonStartRestart = (Button) preview.findViewById(R.id.button_restart);
|
|
mButtonStartRestart.setOnClickListener(v -> {
|
|
final int firstPos = viewPager.getCurrentItem() - mViewPagerItems.length;
|
|
viewPager.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 = viewPager.getCurrentItem() + 1;
|
|
viewPager.setCurrentItem(nextPos, true);
|
|
});
|
|
|
|
viewPager.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(@NonNull ViewGroup container, int position,
|
|
@NonNull Object object) {
|
|
if (mPageViewList.get(position) != null) {
|
|
container.removeView(mPageViewList.get(position));
|
|
}
|
|
}
|
|
|
|
@NonNull
|
|
@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(@NonNull View view, @NonNull 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);
|
|
}
|
|
}
|