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