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.content.Intent.EXTRA_USER_ID; 20 21 import android.annotation.IntDef; 22 import android.app.Activity; 23 import android.content.Context; 24 import android.content.res.ColorStateList; 25 import android.os.Bundle; 26 import android.os.UserHandle; 27 import android.os.UserManager; 28 import android.text.TextUtils; 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.fragment.app.FragmentStatePagerAdapter; 38 import androidx.recyclerview.widget.RecyclerView; 39 import androidx.viewpager.widget.ViewPager; 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 48 import java.lang.annotation.Retention; 49 import java.lang.annotation.RetentionPolicy; 50 import java.util.Locale; 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 private static final int[] LABEL = { 100 R.string.category_personal, R.string.category_work 101 }; 102 103 private ViewGroup mContentView; 104 105 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)106 public View onCreateView(LayoutInflater inflater, ViewGroup container, 107 Bundle savedInstanceState) { 108 mContentView = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState); 109 final Activity activity = getActivity(); 110 final int selectedTab = convertPosition(getTabId(activity, getArguments())); 111 112 final View tabContainer = mContentView.findViewById(R.id.tab_container); 113 final ViewPager viewPager = tabContainer.findViewById(R.id.view_pager); 114 viewPager.setAdapter(new ProfileSelectFragment.ViewPagerAdapter(this)); 115 final TabLayout tabs = tabContainer.findViewById(R.id.tabs); 116 tabs.setupWithViewPager(viewPager); 117 setupTabTextColor(tabs); 118 tabContainer.setVisibility(View.VISIBLE); 119 final TabLayout.Tab tab = tabs.getTabAt(selectedTab); 120 tab.select(); 121 122 final FrameLayout listContainer = mContentView.findViewById(android.R.id.list_container); 123 listContainer.setLayoutParams(new LinearLayout.LayoutParams( 124 ViewGroup.LayoutParams.MATCH_PARENT, 125 ViewGroup.LayoutParams.WRAP_CONTENT)); 126 127 final RecyclerView recyclerView = getListView(); 128 recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); 129 Utils.setActionBarShadowAnimation(activity, getSettingsLifecycle(), recyclerView); 130 131 return mContentView; 132 } 133 134 /** 135 * TabLayout uses ColorStateList of 2 states, selected state and empty state. 136 * It's expected to use textColorSecondary default state color as empty state tabTextColor. 137 * 138 * However, TabLayout uses textColorSecondary by a not expected state. 139 * This method sets tabTextColor with the color of expected textColorSecondary state. 140 */ setupTabTextColor(TabLayout tabLayout)141 private void setupTabTextColor(TabLayout tabLayout) { 142 final ColorStateList defaultColorStateList = tabLayout.getTabTextColors(); 143 final ColorStateList resultColorStateList = new ColorStateList( 144 new int[][]{ 145 new int[]{android.R.attr.state_selected}, 146 new int[]{} 147 }, 148 new int[] { 149 defaultColorStateList.getColorForState(new int[]{android.R.attr.state_selected}, 150 Utils.getColorAttrDefaultColor(getContext(), 151 com.android.internal.R.attr.colorAccentPrimaryVariant)), 152 Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorSecondary) 153 } 154 ); 155 tabLayout.setTabTextColors(resultColorStateList); 156 } 157 158 @Override getMetricsCategory()159 public int getMetricsCategory() { 160 return METRICS_CATEGORY_UNKNOWN; 161 } 162 163 /** 164 * Returns an array of {@link Fragment} to display in the 165 * {@link com.google.android.material.tabs.TabLayout} 166 */ getFragments()167 public abstract Fragment[] getFragments(); 168 169 @Override getPreferenceScreenResId()170 protected int getPreferenceScreenResId() { 171 return R.xml.placeholder_preference_screen; 172 } 173 174 @Override getLogTag()175 protected String getLogTag() { 176 return TAG; 177 } 178 179 @VisibleForTesting getTabId(Activity activity, Bundle bundle)180 int getTabId(Activity activity, Bundle bundle) { 181 if (bundle != null) { 182 final int extraTab = bundle.getInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, -1); 183 if (extraTab != -1) { 184 return extraTab; 185 } 186 final int userId = bundle.getInt(EXTRA_USER_ID, UserHandle.SYSTEM.getIdentifier()); 187 final boolean isWorkProfile = UserManager.get(activity).isManagedProfile(userId); 188 if (isWorkProfile) { 189 return WORK_TAB; 190 } 191 } 192 // Start intent from a specific user eg: adb shell --user 10 193 final int intentUser = activity.getIntent().getContentUserHint(); 194 if (UserManager.get(activity).isManagedProfile(intentUser)) { 195 return WORK_TAB; 196 } 197 198 return PERSONAL_TAB; 199 } 200 201 static class ViewPagerAdapter extends FragmentStatePagerAdapter { 202 203 private final Fragment[] mChildFragments; 204 private final Context mContext; 205 ViewPagerAdapter(ProfileSelectFragment fragment)206 ViewPagerAdapter(ProfileSelectFragment fragment) { 207 super(fragment.getChildFragmentManager()); 208 mContext = fragment.getContext(); 209 mChildFragments = fragment.getFragments(); 210 } 211 212 @Override getItem(int position)213 public Fragment getItem(int position) { 214 return mChildFragments[convertPosition(position)]; 215 } 216 217 @Override getCount()218 public int getCount() { 219 return mChildFragments.length; 220 } 221 222 @Override getPageTitle(int position)223 public CharSequence getPageTitle(int position) { 224 return mContext.getString(LABEL[convertPosition(position)]); 225 } 226 } 227 convertPosition(int index)228 private static int convertPosition(int index) { 229 if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) 230 == View.LAYOUT_DIRECTION_RTL) { 231 return LABEL.length - 1 - index; 232 } 233 return index; 234 } 235 } 236