• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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.settings.dashboard.profileselector;
18 
19 import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
20 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
21 import static android.content.Intent.EXTRA_USER_ID;
22 
23 import android.annotation.IntDef;
24 import android.app.Activity;
25 import android.app.admin.DevicePolicyManager;
26 import android.os.Bundle;
27 import android.os.UserHandle;
28 import android.os.UserManager;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.widget.FrameLayout;
33 import android.widget.LinearLayout;
34 
35 import androidx.annotation.VisibleForTesting;
36 import androidx.fragment.app.Fragment;
37 import androidx.recyclerview.widget.RecyclerView;
38 import androidx.viewpager2.adapter.FragmentStateAdapter;
39 import androidx.viewpager2.widget.ViewPager2;
40 
41 import com.android.settings.R;
42 import com.android.settings.SettingsActivity;
43 import com.android.settings.Utils;
44 import com.android.settings.dashboard.DashboardFragment;
45 
46 import com.google.android.material.tabs.TabLayout;
47 import com.google.android.material.tabs.TabLayoutMediator;
48 
49 import java.lang.annotation.Retention;
50 import java.lang.annotation.RetentionPolicy;
51 
52 /**
53  * Base fragment class for profile settings.
54  */
55 public abstract class ProfileSelectFragment extends DashboardFragment {
56 
57     private static final String TAG = "ProfileSelectFragment";
58 
59     /**
60      * Denotes the profile type.
61      */
62     @Retention(RetentionPolicy.SOURCE)
63     @IntDef({
64             ProfileType.PERSONAL,
65             ProfileType.WORK,
66             ProfileType.ALL
67     })
68     public @interface ProfileType {
69         /**
70          * It is personal work profile.
71          */
72         int PERSONAL = 1;
73 
74         /**
75          * It is work profile
76          */
77         int WORK = 1 << 1;
78 
79         /**
80          * It is personal and work profile
81          */
82         int ALL = PERSONAL | WORK;
83     }
84 
85     /**
86      * Used in fragment argument and pass {@link ProfileType} to it
87      */
88     public static final String EXTRA_PROFILE = "profile";
89 
90     /**
91      * Used in fragment argument with Extra key {@link SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB}
92      */
93     public static final int PERSONAL_TAB = 0;
94 
95     /**
96      * Used in fragment argument with Extra key {@link SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB}
97      */
98     public static final int WORK_TAB = 1;
99 
100     private ViewGroup mContentView;
101 
102     private ViewPager2 mViewPager;
103 
104     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)105     public View onCreateView(LayoutInflater inflater, ViewGroup container,
106             Bundle savedInstanceState) {
107         mContentView = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
108         final Activity activity = getActivity();
109         final int titleResId = getTitleResId();
110         if (titleResId > 0) {
111             activity.setTitle(titleResId);
112         }
113         final int selectedTab = getTabId(activity, getArguments());
114 
115         final View tabContainer = mContentView.findViewById(R.id.tab_container);
116         mViewPager = tabContainer.findViewById(R.id.view_pager);
117         mViewPager.setAdapter(new ProfileSelectFragment.ViewPagerAdapter(this));
118         final TabLayout tabs = tabContainer.findViewById(R.id.tabs);
119         new TabLayoutMediator(tabs, mViewPager,
120                 (tab, position) -> tab.setText(getPageTitle(position))
121         ).attach();
122         mViewPager.registerOnPageChangeCallback(
123                 new ViewPager2.OnPageChangeCallback() {
124                     @Override
125                     public void onPageSelected(int position) {
126                         super.onPageSelected(position);
127                         updateHeight(position);
128                     }
129                 }
130         );
131         tabContainer.setVisibility(View.VISIBLE);
132         final TabLayout.Tab tab = tabs.getTabAt(selectedTab);
133         tab.select();
134 
135         final FrameLayout listContainer = mContentView.findViewById(android.R.id.list_container);
136         listContainer.setLayoutParams(new LinearLayout.LayoutParams(
137                 ViewGroup.LayoutParams.MATCH_PARENT,
138                 ViewGroup.LayoutParams.WRAP_CONTENT));
139 
140         final RecyclerView recyclerView = getListView();
141         recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
142         Utils.setActionBarShadowAnimation(activity, getSettingsLifecycle(), recyclerView);
143 
144         return mContentView;
145     }
146 
forceUpdateHeight()147     protected boolean forceUpdateHeight() {
148         return false;
149     }
150 
updateHeight(int position)151     private void updateHeight(int position) {
152         if (!forceUpdateHeight()) {
153             return;
154         }
155         ViewPagerAdapter adapter = (ViewPagerAdapter) mViewPager.getAdapter();
156         if (adapter == null || adapter.getItemCount() <= position) {
157             return;
158         }
159 
160         Fragment fragment = adapter.createFragment(position);
161         View newPage = fragment.getView();
162         if (newPage != null) {
163             int viewWidth = View.MeasureSpec.makeMeasureSpec(newPage.getWidth(),
164                     View.MeasureSpec.EXACTLY);
165             int viewHeight = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
166             newPage.measure(viewWidth, viewHeight);
167             int currentHeight = mViewPager.getLayoutParams().height;
168             int newHeight = newPage.getMeasuredHeight();
169             if (newHeight != 0 && currentHeight != newHeight) {
170                 ViewGroup.LayoutParams layoutParams = mViewPager.getLayoutParams();
171                 layoutParams.height = newHeight;
172                 mViewPager.setLayoutParams(layoutParams);
173             }
174         }
175     }
176 
177     @Override
getMetricsCategory()178     public int getMetricsCategory() {
179         return METRICS_CATEGORY_UNKNOWN;
180     }
181 
182     /**
183      * Returns an array of {@link Fragment} to display in the
184      * {@link com.google.android.material.tabs.TabLayout}
185      */
getFragments()186     public abstract Fragment[] getFragments();
187 
188     /**
189      * Returns a resource ID of the title
190      * Override this if the title needs to be updated dynamically.
191      */
getTitleResId()192     public int getTitleResId() {
193         return 0;
194     }
195 
196     @Override
getPreferenceScreenResId()197     protected int getPreferenceScreenResId() {
198         return R.xml.placeholder_preference_screen;
199     }
200 
201     @Override
getLogTag()202     protected String getLogTag() {
203         return TAG;
204     }
205 
206     @VisibleForTesting
getTabId(Activity activity, Bundle bundle)207     int getTabId(Activity activity, Bundle bundle) {
208         if (bundle != null) {
209             final int extraTab = bundle.getInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, -1);
210             if (extraTab != -1) {
211                 return extraTab;
212             }
213             final int userId = bundle.getInt(EXTRA_USER_ID, UserHandle.SYSTEM.getIdentifier());
214             final boolean isWorkProfile = UserManager.get(activity).isManagedProfile(userId);
215             if (isWorkProfile) {
216                 return WORK_TAB;
217             }
218         }
219         // Start intent from a specific user eg: adb shell --user 10
220         final int intentUser = activity.getIntent().getContentUserHint();
221         if (UserManager.get(activity).isManagedProfile(intentUser)) {
222             return WORK_TAB;
223         }
224 
225         return PERSONAL_TAB;
226     }
227 
getPageTitle(int position)228     private CharSequence getPageTitle(int position) {
229         final DevicePolicyManager devicePolicyManager =
230                 getContext().getSystemService(DevicePolicyManager.class);
231 
232         if (position == WORK_TAB) {
233             return devicePolicyManager.getResources().getString(WORK_CATEGORY_HEADER,
234                     () -> getContext().getString(R.string.category_work));
235         }
236 
237         return devicePolicyManager.getResources().getString(PERSONAL_CATEGORY_HEADER,
238                 () -> getContext().getString(R.string.category_personal));
239     }
240 
241     static class ViewPagerAdapter extends FragmentStateAdapter {
242 
243         private final Fragment[] mChildFragments;
244 
ViewPagerAdapter(ProfileSelectFragment fragment)245         ViewPagerAdapter(ProfileSelectFragment fragment) {
246             super(fragment);
247             mChildFragments = fragment.getFragments();
248         }
249 
250         @Override
createFragment(int position)251         public Fragment createFragment(int position) {
252             return mChildFragments[position];
253         }
254 
255         @Override
getItemCount()256         public int getItemCount() {
257             return mChildFragments.length;
258         }
259     }
260 }
261