1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.settings.system;
18 
19 import static android.app.Activity.RESULT_OK;
20 
21 import android.content.Intent;
22 import android.os.Bundle;
23 import android.view.View;
24 import android.view.ViewTreeObserver;
25 
26 import androidx.annotation.Nullable;
27 import androidx.annotation.VisibleForTesting;
28 import androidx.annotation.XmlRes;
29 import androidx.recyclerview.widget.RecyclerView;
30 
31 import com.android.car.settings.R;
32 import com.android.car.settings.common.ActivityResultCallback;
33 import com.android.car.settings.common.SettingsFragment;
34 import com.android.car.settings.security.CheckLockActivity;
35 import com.android.car.ui.toolbar.MenuItem;
36 
37 import java.util.Collections;
38 import java.util.List;
39 
40 /**
41  * Presents the user with the option to reset the head unit to its default "factory" state. If a
42  * user confirms, the user is first required to authenticate and then presented with a secondary
43  * confirmation: {@link MasterClearConfirmFragment}. The user must scroll to the bottom of the page
44  * before proceeding.
45  */
46 public class MasterClearFragment extends SettingsFragment implements ActivityResultCallback {
47 
48     // Arbitrary request code for starting CheckLockActivity when the reset button is clicked.
49     @VisibleForTesting
50     static final int CHECK_LOCK_REQUEST_CODE = 88;
51 
52     private MenuItem mMasterClearButton;
53 
54     @Override
getToolbarMenuItems()55     public List<MenuItem> getToolbarMenuItems() {
56         return Collections.singletonList(mMasterClearButton);
57     }
58 
59     @Override
onCreate(Bundle savedInstanceState)60     public void onCreate(Bundle savedInstanceState) {
61         super.onCreate(savedInstanceState);
62 
63         mMasterClearButton = new MenuItem.Builder(getContext())
64                 .setTitle(R.string.master_clear_button_text)
65                 .setEnabled(false)
66                 .setOnClickListener(i ->
67                         startActivityForResult(new Intent(getContext(), CheckLockActivity.class),
68                                 CHECK_LOCK_REQUEST_CODE, /* callback= */ MasterClearFragment.this))
69                 .build();
70     }
71 
72     @Override
73     @XmlRes
getPreferenceScreenResId()74     protected int getPreferenceScreenResId() {
75         return R.xml.master_clear_fragment;
76     }
77 
78     @Override
onActivityCreated(Bundle savedInstanceState)79     public void onActivityCreated(Bundle savedInstanceState) {
80         super.onActivityCreated(savedInstanceState);
81 
82         RecyclerView recyclerView = getListView();
83         recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(
84                 new ViewTreeObserver.OnGlobalLayoutListener() {
85                     @Override
86                     public void onGlobalLayout() {
87                         mMasterClearButton.setEnabled(isAtEnd());
88                         recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
89                     }
90                 });
91         recyclerView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
92             if (isAtEnd()) {
93                 mMasterClearButton.setEnabled(true);
94             }
95         });
96     }
97 
98     @Override
processActivityResult(int requestCode, int resultCode, @Nullable Intent data)99     public void processActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
100         if (requestCode == CHECK_LOCK_REQUEST_CODE && resultCode == RESULT_OK) {
101             launchFragment(new MasterClearConfirmFragment());
102         }
103     }
104 
105     /** Returns {@code true} if the RecyclerView is completely displaying the last item. */
isAtEnd()106     private boolean isAtEnd() {
107         RecyclerView recyclerView = getListView();
108         RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
109         if (layoutManager == null || layoutManager.getChildCount() == 0) {
110             return true;
111         }
112 
113         int childCount = layoutManager.getChildCount();
114         View lastVisibleChild = layoutManager.getChildAt(childCount - 1);
115 
116         // The list has reached the bottom if the last child that is visible is the last item
117         // in the list and it's fully shown.
118         return layoutManager.getPosition(lastVisibleChild) == (layoutManager.getItemCount() - 1)
119                 && layoutManager.getDecoratedBottom(lastVisibleChild) <= layoutManager.getHeight();
120     }
121 }
122