1 /* 2 * Copyright (C) 2018 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.car.settings.quicksettings; 18 19 import android.app.Activity; 20 import android.app.ActivityManager; 21 import android.car.drivingstate.CarUxRestrictions; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.pm.UserInfo; 25 import android.graphics.drawable.Drawable; 26 import android.os.Build; 27 import android.os.Bundle; 28 import android.os.SystemProperties; 29 import android.os.UserManager; 30 import android.view.View; 31 import android.widget.TextView; 32 33 import androidx.activity.result.ActivityResultLauncher; 34 import androidx.activity.result.contract.ActivityResultContracts; 35 import androidx.annotation.LayoutRes; 36 import androidx.annotation.NonNull; 37 38 import com.android.car.settings.R; 39 import com.android.car.settings.common.BaseFragment; 40 import com.android.car.settings.common.CarSettingActivities; 41 import com.android.car.settings.profiles.ProfileIconProvider; 42 import com.android.car.settings.profiles.ProfileSwitcherActivity; 43 import com.android.car.ui.recyclerview.CarUiRecyclerView; 44 import com.android.car.ui.toolbar.MenuItem; 45 import com.android.car.ui.toolbar.NavButtonMode; 46 47 import java.util.Arrays; 48 import java.util.List; 49 import java.util.concurrent.TimeUnit; 50 51 /** 52 * Shows a page to access frequently used settings. 53 */ 54 public class QuickSettingFragment extends BaseFragment { 55 // Time to delay refreshing the build info, if the clock is not correct. 56 private static final long BUILD_INFO_REFRESH_TIME_MS = TimeUnit.SECONDS.toMillis(5); 57 58 private UserManager mUserManager; 59 private ProfileIconProvider mProfileIconProvider; 60 private QuickSettingGridAdapter mGridAdapter; 61 private CarUiRecyclerView mListView; 62 private MenuItem mFullSettingsBtn; 63 private MenuItem mProfileSwitcherBtn; 64 private TextView mBuildInfo; 65 66 private ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult( 67 new ActivityResultContracts.StartActivityForResult(), 68 result -> { 69 if (result.getResultCode() == Activity.FINISH_TASK_WITH_ACTIVITY) { 70 getActivity().finish(); 71 } 72 }); 73 74 @Override 75 @LayoutRes getLayoutId()76 protected int getLayoutId() { 77 return R.layout.quick_settings; 78 } 79 80 @Override onActivityCreated(Bundle savedInstanceState)81 public void onActivityCreated(Bundle savedInstanceState) { 82 super.onActivityCreated(savedInstanceState); 83 mUserManager = UserManager.get(getContext()); 84 Activity activity = requireActivity(); 85 86 mProfileIconProvider = new ProfileIconProvider(); 87 mListView = activity.findViewById(R.id.quick_settings_list); 88 mGridAdapter = new QuickSettingGridAdapter(activity); 89 mListView.setLayoutManager(mGridAdapter.getGridLayoutManager()); 90 91 setupProfileButton(activity); 92 93 mGridAdapter 94 .addTile(new WifiTile(activity, mGridAdapter, getLifecycle())) 95 .addTile(new BluetoothTile(activity, mGridAdapter, getFragmentHost())) 96 .addTile(new DayNightTile(activity, mGridAdapter, getFragmentHost())) 97 .addTile(new CelluarTile(activity, mGridAdapter, getFragmentHost())) 98 .addSeekbarTile(new BrightnessTile(activity)); 99 mListView.setAdapter(mGridAdapter); 100 } 101 102 103 @Override getToolbarNavButtonStyle()104 protected NavButtonMode getToolbarNavButtonStyle() { 105 if (getContext().getResources().getBoolean(R.bool.config_is_quick_settings_root) 106 && !getContext().getResources() 107 .getBoolean(R.bool.config_show_settings_root_exit_icon)) { 108 return NavButtonMode.DISABLED; 109 } else { 110 return NavButtonMode.CLOSE; 111 } 112 } 113 114 @Override getToolbarMenuItems()115 public List<MenuItem> getToolbarMenuItems() { 116 return Arrays.asList(mProfileSwitcherBtn, mFullSettingsBtn); 117 } 118 119 @Override onCreate(Bundle savedInstanceState)120 public void onCreate(Bundle savedInstanceState) { 121 super.onCreate(savedInstanceState); 122 123 mProfileSwitcherBtn = new MenuItem.Builder(getContext()) 124 .setTitle(getString(R.string.user_switch)) 125 .setOnClickListener(i -> 126 mStartForResult.launch( 127 new Intent(getContext(), ProfileSwitcherActivity.class))) 128 .setIcon(R.drawable.ic_profile) 129 .setShowIconAndTitle(true) 130 .setVisible(showProfileSwitcher()) 131 .setTinted(false) 132 .build(); 133 mFullSettingsBtn = new MenuItem.Builder(getContext()) 134 .setTitle(getString(R.string.more_settings_label)) 135 .setOnClickListener(i -> launchFullSettings()) 136 .setIcon(R.drawable.ic_settings_gear) 137 .setShowIconAndTitle(true) 138 .setUxRestrictions(CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP) 139 .build(); 140 } 141 142 @Override onViewCreated(@onNull View view, Bundle savedInstanceState)143 public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { 144 super.onViewCreated(view, savedInstanceState); 145 146 mBuildInfo = view.requireViewById(R.id.build_info); 147 } 148 149 @Override onStart()150 public void onStart() { 151 super.onStart(); 152 mGridAdapter.start(); 153 154 // In non-user builds (that is, user-debug, eng, etc), display some version information. 155 if (!Build.IS_USER) { 156 refreshBuildInfo(); 157 } 158 } 159 launchFullSettings()160 private void launchFullSettings() { 161 startActivity(new Intent(getContext(), CarSettingActivities.HomepageActivity.class)); 162 if (!getContext().getResources().getBoolean(R.bool.config_is_quick_settings_root)) { 163 getActivity().finish(); 164 } 165 } 166 refreshBuildInfo()167 private void refreshBuildInfo() { 168 if (!isAdded()) { 169 // This can happen if the delayed post happens before we're stopped. Just give up 170 // trying to get the right clock. 171 return; 172 } 173 174 long buildTimeDiffDays = 175 TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - Build.TIME); 176 if (buildTimeDiffDays < 0) { 177 // If it's in the past, that likely means the current time is wrong (or the build time 178 // could be wrong, but that's less likely). Reschedule this to run in a few seconds to 179 // see whether the clock's been fixed. 180 mBuildInfo.postDelayed(this::refreshBuildInfo, BUILD_INFO_REFRESH_TIME_MS); 181 } 182 183 String str = String.format(getResources().getString(R.string.build_info_fmt), 184 Build.FINGERPRINT, SystemProperties.get("ro.build.date", "<unknown>"), 185 buildTimeDiffDays < 0 ? "--" : Long.toString(buildTimeDiffDays)); 186 187 mBuildInfo.setVisibility(View.VISIBLE); 188 mBuildInfo.setText(str); 189 } 190 191 @Override onStop()192 public void onStop() { 193 super.onStop(); 194 mGridAdapter.stop(); 195 } 196 setupProfileButton(Context context)197 private void setupProfileButton(Context context) { 198 UserInfo currentUserInfo = mUserManager.getUserInfo(ActivityManager.getCurrentUser()); 199 Drawable profileIcon = mProfileIconProvider.getDrawableWithBadge(context, currentUserInfo); 200 mProfileSwitcherBtn.setIcon(profileIcon); 201 mProfileSwitcherBtn.setTitle(currentUserInfo.name); 202 } 203 showProfileSwitcher()204 private boolean showProfileSwitcher() { 205 return !UserManager.isDeviceInDemoMode(getContext()) 206 && UserManager.supportsMultipleUsers() 207 && !UserManager.get(getContext()).hasUserRestriction( 208 UserManager.DISALLOW_USER_SWITCH); 209 } 210 211 /** 212 * Quick Settings should be viewable while driving 213 */ 214 @Override canBeShown(@onNull CarUxRestrictions carUxRestrictions)215 protected boolean canBeShown(@NonNull CarUxRestrictions carUxRestrictions) { 216 return true; 217 } 218 } 219