PermissionsFrameFragment.java revision ef861375eebd9ac6cce7c0bb163380ab1c951063
1ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav/* 2ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * Copyright (C) 2015 The Android Open Source Project 3ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * 4ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * Licensed under the Apache License, Version 2.0 (the "License"); 5ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * you may not use this file except in compliance with the License. 6ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * You may obtain a copy of the License at 7ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * 8ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * http://www.apache.org/licenses/LICENSE-2.0 9ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * 10ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * Unless required by applicable law or agreed to in writing, software 11ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * distributed under the License is distributed on an "AS IS" BASIS, 12ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * See the License for the specific language governing permissions and 14ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * limitations under the License. 15ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav */ 16ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 17ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavpackage com.android.packageinstaller.permission.ui.television; 18ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 19ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.annotation.Nullable; 20ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.os.Bundle; 21ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.support.v14.preference.PreferenceFragment; 22ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.support.v17.leanback.widget.VerticalGridView; 23ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.support.v7.preference.PreferenceScreen; 24ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.support.v7.widget.RecyclerView; 25ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.support.v7.widget.RecyclerView.AdapterDataObserver; 26ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.view.LayoutInflater; 27ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.view.View; 28ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.view.ViewGroup; 29ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.view.animation.Animation; 30ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.view.animation.Animation.AnimationListener; 31ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.view.animation.AnimationUtils; 32ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport android.widget.TextView; 33ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 34ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport com.android.packageinstaller.R; 35ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavimport com.android.packageinstaller.permission.utils.Utils; 36ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 37ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslavpublic abstract class PermissionsFrameFragment extends PreferenceFragment { 38ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 39ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav private static final float WINDOW_ALIGNMENT_OFFSET_PERCENT = 50; 40ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 41ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav private ViewGroup mPreferencesContainer; 42ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 43ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav // TV-specific instance variables 44ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Nullable private VerticalGridView mGridView; 45ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 46ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav private View mLoadingView; 47ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav private ViewGroup mPrefsView; 48ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav private boolean mIsLoading; 49ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 50ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav /** 51ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * Returns the view group that holds the preferences objects. This will 52ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * only be set after {@link #onCreateView} has been called. 53ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav */ 54ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav protected final ViewGroup getPreferencesContainer() { 55ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav return mPreferencesContainer; 56ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 57ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 58ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 59ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav public View onCreateView(LayoutInflater inflater, ViewGroup container, 60ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav Bundle savedInstanceState) { 61ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.permissions_frame, container, 62ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav false); 63ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mPrefsView = (ViewGroup) rootView.findViewById(R.id.prefs_container); 64ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (mPrefsView == null) { 65ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mPrefsView = rootView; 66ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 67ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mLoadingView = rootView.findViewById(R.id.loading_container); 68ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mPreferencesContainer = (ViewGroup) super.onCreateView( 69ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav inflater, mPrefsView, savedInstanceState); 70ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav setLoading(mIsLoading, false, true /* force */); 71ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mPrefsView.addView(mPreferencesContainer); 72ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav return rootView; 73ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 74ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 75ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 76ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { 77ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav PreferenceScreen preferences = getPreferenceScreen(); 78ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (preferences == null) { 79ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav preferences = getPreferenceManager().createPreferenceScreen(getActivity()); 80ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav setPreferenceScreen(preferences); 81ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 82ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 83ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 84ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav protected void setLoading(boolean loading, boolean animate) { 85ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav setLoading(loading, animate, false); 86ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 87ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 88ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav private void setLoading(boolean loading, boolean animate, boolean force) { 89ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (mIsLoading != loading || force) { 90ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mIsLoading = loading; 91ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (getView() == null) { 92ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav // If there is no created view, there is no reason to animate. 93ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav animate = false; 94ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 95ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (mPrefsView != null) { 96ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav setViewShown(mPrefsView, !loading, animate); 97ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 98ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (mLoadingView != null) { 99ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav setViewShown(mLoadingView, loading, animate); 100ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 101ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 102ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 103ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 104ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav private void setViewShown(final View view, boolean shown, boolean animate) { 105ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (animate) { 106ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav Animation animation = AnimationUtils.loadAnimation(getContext(), 107ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav shown ? android.R.anim.fade_in : android.R.anim.fade_out); 108ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (shown) { 109ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav view.setVisibility(View.VISIBLE); 110ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } else { 111ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav animation.setAnimationListener(new AnimationListener() { 112ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 113ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav public void onAnimationStart(Animation animation) { 114ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 115ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 116ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 117ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav public void onAnimationRepeat(Animation animation) { 118ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 119ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 120ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 121ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav public void onAnimationEnd(Animation animation) { 122ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav view.setVisibility(View.INVISIBLE); 123ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 124ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav }); 125ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 126ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav view.startAnimation(animation); 127ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } else { 128ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav view.clearAnimation(); 129ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav view.setVisibility(shown ? View.VISIBLE : View.INVISIBLE); 130ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 131ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 132ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 133ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 134ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, 135ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav Bundle savedInstanceState) { 136ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (Utils.isTelevision(getContext())) { 137ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mGridView = (VerticalGridView) inflater.inflate( 138ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav R.layout.leanback_preferences_list, parent, false); 139ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mGridView.setWindowAlignmentOffset(0); 140ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mGridView.setWindowAlignmentOffsetPercent(WINDOW_ALIGNMENT_OFFSET_PERCENT); 141ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE); 142ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mGridView.setFocusScrollStrategy(VerticalGridView.FOCUS_SCROLL_ALIGNED); 143ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav return mGridView; 144ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } else { 145ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav return super.onCreateRecyclerView(inflater, parent, savedInstanceState); 146ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 147ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 148ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 149ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 150ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav protected RecyclerView.Adapter<?> onCreateAdapter(PreferenceScreen preferenceScreen) { 151ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav final RecyclerView.Adapter<?> adapter = super.onCreateAdapter(preferenceScreen); 152ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 153ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (adapter != null) { 154ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav final TextView emptyView = (TextView) getView().findViewById(R.id.no_permissions); 155ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav onSetEmptyText(emptyView); 156ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav final RecyclerView recyclerView = getListView(); 157ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav adapter.registerAdapterDataObserver(new AdapterDataObserver() { 158ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 159ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav public void onChanged() { 160ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav checkEmpty(); 161ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 162ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 163ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 164ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav public void onItemRangeInserted(int positionStart, int itemCount) { 165ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav checkEmpty(); 166ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 167ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 168ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav @Override 169ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav public void onItemRangeRemoved(int positionStart, int itemCount) { 170ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav checkEmpty(); 171ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 172ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 173ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav private void checkEmpty() { 174ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav boolean isEmpty = adapter.getItemCount() == 0; 175ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav emptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE); 176ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav recyclerView.setVisibility(isEmpty ? View.GONE : View.VISIBLE); 177ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (!isEmpty && mGridView != null) { 178ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mGridView.requestFocus(); 179ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 180ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 181ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav }); 182ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 183ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav boolean isEmpty = adapter.getItemCount() == 0; 184ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav emptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE); 185ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav recyclerView.setVisibility(isEmpty ? View.GONE : View.VISIBLE); 186ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav if (!isEmpty && mGridView != null) { 187ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav mGridView.requestFocus(); 188ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 189ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 190ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 191ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav return adapter; 192ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 193ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 194ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav /** 195ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * Hook for subclasses to change the default text of the empty view. 196ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * Base implementation leaves the default empty view text. 197ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * 198ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav * @param textView the empty text view 199ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav */ 200ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav protected void onSetEmptyText(TextView textView) { 201ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav } 202ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav} 203ef861375eebd9ac6cce7c0bb163380ab1c951063Svetoslav 204