• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.permissioncontroller.permission.ui.handheld;
18 
19 import android.app.ActionBar;
20 import android.os.Bundle;
21 import android.view.LayoutInflater;
22 import android.view.Menu;
23 import android.view.MenuInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.view.animation.Animation;
27 import android.view.animation.Animation.AnimationListener;
28 import android.view.animation.AnimationUtils;
29 import android.widget.TextView;
30 
31 import androidx.annotation.NonNull;
32 import androidx.preference.PreferenceFragmentCompat;
33 import androidx.preference.PreferenceScreen;
34 import androidx.recyclerview.widget.RecyclerView;
35 
36 import com.android.modules.utils.build.SdkLevel;
37 import com.android.permissioncontroller.DeviceUtils;
38 import com.android.permissioncontroller.R;
39 import com.android.permissioncontroller.permission.ui.handheld.v35.SectionPreferenceGroupAdapter;
40 import com.android.permissioncontroller.permission.utils.Utils;
41 import com.android.settingslib.widget.ActionBarShadowController;
42 
43 public abstract class PermissionsFrameFragment extends PreferenceFragmentCompat {
44     private static final String LOG_TAG = PermissionsFrameFragment.class.getSimpleName();
45 
46     static final int MENU_ALL_PERMS = Menu.FIRST + 1;
47     public static final int MENU_SHOW_SYSTEM = Menu.FIRST + 2;
48     public static final int MENU_HIDE_SYSTEM = Menu.FIRST + 3;
49     static final int MENU_ALLOW_RESTRICTED_SETTINGS = Menu.FIRST + 4;
50 
51     private ViewGroup mPreferencesContainer;
52 
53     private TextView mEmptyView;
54     private View mLoadingView;
55     private View mProgressHeader;
56     private View mProgressView;
57     private ViewGroup mPrefsView;
58     private boolean mIsLoading;
59 
60     protected boolean mUseShadowController = true;
61 
62     /**
63      * Returns the view group that holds the preferences objects. This will
64      * only be set after {@link #onCreateView} has been called.
65      */
getPreferencesContainer()66     protected final ViewGroup getPreferencesContainer() {
67         return mPreferencesContainer;
68     }
69 
70     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)71     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
72         super.onCreateOptionsMenu(menu, inflater);
73 
74         if (!SdkLevel.isAtLeastS()) {
75             Utils.prepareSearchMenuItem(menu, requireContext());
76         }
77     }
78 
79     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)80     public View onCreateView(LayoutInflater inflater, ViewGroup container,
81             Bundle savedInstanceState) {
82         ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.permissions_frame, container,
83                         false);
84         mPrefsView = (ViewGroup) rootView.findViewById(R.id.prefs_container);
85         if (mPrefsView == null) {
86             mPrefsView = rootView;
87         }
88         mEmptyView = mPrefsView.findViewById(R.id.no_permissions);
89         mEmptyView.setText(getEmptyViewString());
90         mLoadingView = rootView.findViewById(R.id.loading_container);
91         mPreferencesContainer = (ViewGroup) super.onCreateView(
92                 inflater, mPrefsView, savedInstanceState);
93         setLoading(mIsLoading, false, true /* force */);
94         mPrefsView.addView(mPreferencesContainer);
95         mProgressHeader = rootView.requireViewById(
96                 com.android.settingslib.widget.progressbar.R.id.progress_bar_animation);
97         mProgressView = rootView.requireViewById(
98                 com.android.settingslib.widget.progressbar.R.id.progress_bar_background);
99         setProgressBarVisible(false);
100         getListView().setFocusable(false);
101         return rootView;
102     }
103 
104     @Override
onStart()105     public void onStart() {
106         super.onStart();
107 
108         if (getListView() != null) {
109             ActionBar ab = getActivity().getActionBar();
110             if (ab != null) {
111                 ab.setElevation(0);
112             }
113             if (mUseShadowController) {
114                 ActionBarShadowController.attachToView(getActivity(), getLifecycle(),
115                         getListView());
116             }
117         }
118     }
119 
120     @Override
onCreatePreferences(Bundle bundle, String s)121     public void onCreatePreferences(Bundle bundle, String s) {
122         // empty
123     }
124 
125     @Override
onCreateAdapter(@onNull PreferenceScreen preferenceScreen)126     public RecyclerView.Adapter onCreateAdapter(@NonNull PreferenceScreen preferenceScreen) {
127         if (SdkLevel.isAtLeastV() && DeviceUtils.isHandheld(requireContext())) {
128             return new SectionPreferenceGroupAdapter(preferenceScreen);
129         } else {
130             return super.onCreateAdapter(preferenceScreen);
131         }
132     }
133 
setLoading(boolean loading, boolean animate)134     protected void setLoading(boolean loading, boolean animate) {
135         setLoading(loading, animate, false);
136     }
137 
setLoading(boolean loading, boolean animate, boolean force)138     private void setLoading(boolean loading, boolean animate, boolean force) {
139         if (mIsLoading != loading || force) {
140             mIsLoading = loading;
141             if (getView() == null) {
142                 // If there is no created view, there is no reason to animate.
143                 animate = false;
144             }
145             if (mPrefsView != null) {
146                 setViewShown(mPrefsView, !loading, animate);
147             }
148             if (mLoadingView != null) {
149                 setViewShown(mLoadingView, loading, animate);
150             }
151         }
152     }
153 
setProgressBarVisible(boolean visible)154     protected void setProgressBarVisible(boolean visible) {
155         mProgressHeader.setVisibility(visible ? View.VISIBLE : View.GONE);
156         mProgressView.setVisibility(visible ? View.VISIBLE : View.GONE);
157     }
158 
159     /**
160      * Either show the empty view or the recycler view. To be called any time the adapter changes.
161      */
updateEmptyState()162     void updateEmptyState() {
163         RecyclerView prefs = getListView();
164 
165         // This might be called before onCreateView, hence emptyView and prefs can be null
166         if (mEmptyView != null && prefs != null) {
167             if (prefs.getAdapter() != null && prefs.getAdapter().getItemCount() != 0) {
168                 mEmptyView.setVisibility(View.GONE);
169                 prefs.setVisibility(View.VISIBLE);
170             } else {
171                 mEmptyView.setVisibility(View.VISIBLE);
172                 prefs.setVisibility(View.GONE);
173             }
174         }
175     }
176 
177     @Override
onBindPreferences()178     protected void onBindPreferences() {
179         super.onBindPreferences();
180 
181         RecyclerView.Adapter adapter = getListView().getAdapter();
182 
183         if (adapter != null) {
184             adapter.registerAdapterDataObserver(
185                     new RecyclerView.AdapterDataObserver() {
186                         @Override
187                         public void onChanged() {
188                             updateEmptyState();
189                         }
190 
191                         @Override
192                         public void onItemRangeInserted(int positionStart, int itemCount) {
193                             updateEmptyState();
194                         }
195 
196                         @Override
197                         public void onItemRangeRemoved(int positionStart, int itemCount) {
198                             updateEmptyState();
199                         }
200                     });
201         }
202 
203         updateEmptyState();
204     }
205 
setViewShown(final View view, boolean shown, boolean animate)206     private void setViewShown(final View view, boolean shown, boolean animate) {
207         // Clear out previous animation listeners.
208         if (view.getAnimation() != null) {
209             view.getAnimation().setAnimationListener(null);
210         }
211         view.clearAnimation();
212         if (animate) {
213             Animation animation = AnimationUtils.loadAnimation(getContext(),
214                     shown ? android.R.anim.fade_in : android.R.anim.fade_out);
215             if (shown) {
216                 view.setVisibility(View.VISIBLE);
217             } else {
218                 animation.setAnimationListener(new AnimationListener() {
219                     @Override
220                     public void onAnimationStart(Animation animation) {
221                     }
222 
223                     @Override
224                     public void onAnimationRepeat(Animation animation) {
225                     }
226 
227                     @Override
228                     public void onAnimationEnd(Animation animation) {
229                         view.setVisibility(View.INVISIBLE);
230                     }
231                 });
232             }
233             view.startAnimation(animation);
234         } else {
235             view.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
236         }
237     }
238 
239     /**
240      * @return the id of the string to display when there are no entries to show.
241      */
getEmptyViewString()242     public int getEmptyViewString() {
243         return R.string.no_permissions;
244     }
245 }
246