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.recyclerview.CarUiRecyclerView;
36 import com.android.car.ui.toolbar.MenuItem;
37 
38 import java.util.Collections;
39 import java.util.List;
40 
41 /**
42  * Presents the user with the option to reset the head unit to its default "factory" state. If a
43  * user confirms, the user is first required to authenticate and then presented with a secondary
44  * confirmation: {@link MasterClearConfirmFragment}. The user must scroll to the bottom of the page
45  * before proceeding.
46  */
47 public class MasterClearFragment extends SettingsFragment implements ActivityResultCallback {
48 
49     // Arbitrary request code for starting CheckLockActivity when the reset button is clicked.
50     @VisibleForTesting
51     static final int CHECK_LOCK_REQUEST_CODE = 88;
52 
53     private MenuItem mMasterClearButton;
54 
55     @Override
getToolbarMenuItems()56     public List<MenuItem> getToolbarMenuItems() {
57         return Collections.singletonList(mMasterClearButton);
58     }
59 
60     @Override
onCreate(Bundle savedInstanceState)61     public void onCreate(Bundle savedInstanceState) {
62         super.onCreate(savedInstanceState);
63 
64         mMasterClearButton = new MenuItem.Builder(getContext())
65                 .setTitle(R.string.master_clear_button_text)
66                 .setEnabled(false)
67                 .setOnClickListener(i ->
68                         startActivityForResult(new Intent(getContext(), CheckLockActivity.class),
69                                 CHECK_LOCK_REQUEST_CODE, /* callback= */ MasterClearFragment.this))
70                 .build();
71     }
72 
73     @Override
74     @XmlRes
getPreferenceScreenResId()75     protected int getPreferenceScreenResId() {
76         return R.xml.master_clear_fragment;
77     }
78 
79     @Override
onActivityCreated(Bundle savedInstanceState)80     public void onActivityCreated(Bundle savedInstanceState) {
81         super.onActivityCreated(savedInstanceState);
82 
83         RecyclerView recyclerView = getListView();
84         recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(
85                 new ViewTreeObserver.OnGlobalLayoutListener() {
86                     @Override
87                     public void onGlobalLayout() {
88                         if (recyclerView instanceof CarUiRecyclerView) {
89                             CarUiRecyclerView pagedRecyclerView = (CarUiRecyclerView) recyclerView;
90                             if (!pagedRecyclerView.fullyInitialized()) {
91                                 return;
92                             }
93                         }
94                         mMasterClearButton.setEnabled(isAtEnd());
95                         recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
96                     }
97                 });
98         recyclerView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
99             if (isAtEnd()) {
100                 mMasterClearButton.setEnabled(true);
101             }
102         });
103     }
104 
105     @Override
processActivityResult(int requestCode, int resultCode, @Nullable Intent data)106     public void processActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
107         if (requestCode == CHECK_LOCK_REQUEST_CODE && resultCode == RESULT_OK) {
108             launchFragment(new MasterClearConfirmFragment());
109         }
110     }
111 
112     /** Returns {@code true} if the RecyclerView is completely displaying the last item. */
isAtEnd()113     private boolean isAtEnd() {
114         RecyclerView recyclerView = getListView();
115         RecyclerView.LayoutManager layoutManager = (recyclerView instanceof CarUiRecyclerView)
116                 ? ((CarUiRecyclerView) recyclerView).getEffectiveLayoutManager()
117                 : recyclerView.getLayoutManager();
118         if (layoutManager == null || layoutManager.getChildCount() == 0) {
119             return true;
120         }
121 
122         int childCount = layoutManager.getChildCount();
123         View lastVisibleChild = layoutManager.getChildAt(childCount - 1);
124 
125         // The list has reached the bottom if the last child that is visible is the last item
126         // in the list and it's fully shown.
127         return layoutManager.getPosition(lastVisibleChild) == (layoutManager.getItemCount() - 1)
128                 && layoutManager.getDecoratedBottom(lastVisibleChild) <= layoutManager.getHeight();
129     }
130 }
131