1 /* 2 * Copyright (C) 2014 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.tv.settings.about; 18 19 import com.android.tv.settings.R; 20 import com.android.tv.settings.PreferenceUtils; 21 import com.android.tv.settings.dialog.old.Action; 22 import com.android.tv.settings.dialog.old.ActionAdapter; 23 import com.android.tv.settings.dialog.old.ActionFragment; 24 import com.android.tv.settings.dialog.old.ContentFragment; 25 import com.android.tv.settings.dialog.old.DialogActivity; 26 import com.android.tv.settings.name.DeviceManager; 27 28 import android.app.Fragment; 29 import android.app.FragmentTransaction; 30 import android.content.ActivityNotFoundException; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.pm.ApplicationInfo; 35 import android.content.pm.PackageManager; 36 import android.content.pm.ResolveInfo; 37 import android.os.Build; 38 import android.os.Bundle; 39 import android.os.PowerManager; 40 import android.os.SystemClock; 41 import android.text.TextUtils; 42 import android.util.Log; 43 import android.widget.Toast; 44 45 import java.util.ArrayList; 46 import java.util.List; 47 48 /** 49 * Activity which shows the build / model / legal info / etc. 50 */ 51 public class AboutActivity extends DialogActivity implements ActionAdapter.Listener, 52 ActionAdapter.OnFocusListener { 53 54 private static final String TAG = "AboutActivity"; 55 56 /** 57 * Action keys for switching over in onActionClicked. 58 */ 59 private static final String KEY_LEGAL_INFO = "about_legal_info"; 60 private static final String KEY_BUILD = "build"; 61 private static final String KEY_VERSION = "version"; 62 private static final String KEY_REBOOT = "reboot"; 63 64 /** 65 * Intent action of SettingsLicenseActivity (for displaying open source licenses.) 66 */ 67 private static final String SETTINGS_LEGAL_LICENSE_INTENT_ACTION = "android.settings.LICENSE"; 68 69 /** 70 * Intent action of SettingsTosActivity (for displaying terms of service.) 71 */ 72 private static final String SETTINGS_LEGAL_TERMS_OF_SERVICE = "android.settings.TERMS"; 73 74 /** 75 * Intent action of device name activity. 76 */ 77 private static final String SETTINGS_DEVICE_NAME_INTENT_ACTION = "android.settings.DEVICE_NAME"; 78 79 /** 80 * Intent action of system update activity. 81 */ 82 private static final String SETTINGS_UPDATE_SYSTEM = "android.settings.SYSTEM_UPDATE_SETTINGS"; 83 84 /** 85 * Intent to launch ads activity. 86 */ 87 private static final String SETTINGS_ADS_ACTIVITY_PACKAGE = "com.google.android.gms"; 88 private static final String SETTINGS_ADS_ACTIVITY_ACTION = 89 "com.google.android.gms.settings.ADS_PRIVACY"; 90 91 /** 92 * Intent component to launch PlatLogo Easter egg. 93 */ 94 private static final ComponentName mPlatLogoActivity = new ComponentName("android", 95 "com.android.internal.app.PlatLogoActivity"); 96 97 /** 98 * Number of clicks it takes to be a developer. 99 */ 100 private static final int NUM_DEVELOPER_CLICKS = 7; 101 102 private int mDeveloperClickCount; 103 private PreferenceUtils mPreferenceUtils; 104 private Toast mToast; 105 private int mSelectedIndex; 106 private long[] mHits = new long[3]; 107 private int mHitsIndex; 108 109 @Override 110 protected void onCreate(Bundle savedInstanceState) { 111 super.onCreate(savedInstanceState); 112 mPreferenceUtils = new PreferenceUtils(this); 113 setContentAndActionFragments(ContentFragment.newInstance( 114 getString(R.string.about_preference), null, null, R.drawable.ic_settings_about, 115 getResources().getColor(R.color.icon_background)), 116 ActionFragment.newInstance(getActions())); 117 mSelectedIndex = 0; 118 } 119 120 @Override 121 public void onResume() { 122 super.onResume(); 123 mDeveloperClickCount = 0; 124 } 125 126 @Override 127 public void onActionFocused(Action action) { 128 mSelectedIndex = getActions().indexOf(action); 129 } 130 131 @Override 132 public void onActionClicked(Action action) { 133 final String key = action.getKey(); 134 if (TextUtils.equals(key, KEY_BUILD)) { 135 mDeveloperClickCount++; 136 if (!mPreferenceUtils.isDeveloperEnabled()) { 137 int numLeft = NUM_DEVELOPER_CLICKS - mDeveloperClickCount; 138 if (numLeft < 3 && numLeft > 0) { 139 showToast(getResources().getQuantityString( 140 R.plurals.show_dev_countdown, numLeft, numLeft)); 141 } 142 if (numLeft == 0) { 143 mPreferenceUtils.setDeveloperEnabled(true); 144 showToast(getString(R.string.show_dev_on)); 145 mDeveloperClickCount = 0; 146 } 147 } else { 148 if (mDeveloperClickCount > 3) { 149 showToast(getString(R.string.show_dev_already)); 150 } 151 } 152 } else if (TextUtils.equals(key, KEY_VERSION)) { 153 mHits[mHitsIndex] = SystemClock.uptimeMillis(); 154 mHitsIndex = (mHitsIndex + 1) % mHits.length; 155 if (mHits[mHitsIndex] >= SystemClock.uptimeMillis() - 500) { 156 Intent intent = new Intent(); 157 intent.setComponent(mPlatLogoActivity); 158 startActivity(intent); 159 } 160 } else if (TextUtils.equals(key, KEY_LEGAL_INFO)) { 161 ArrayList<Action> actions = getLegalActions(); 162 setContentAndActionFragments(ContentFragment.newInstance( 163 getString(R.string.about_legal_info), null, null), 164 ActionFragment.newInstance(actions)); 165 } else if (TextUtils.equals(key, KEY_REBOOT)) { 166 PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); 167 pm.reboot(null); 168 } else { 169 Intent intent = action.getIntent(); 170 if (intent != null) { 171 try { 172 startActivity(intent); 173 } catch (ActivityNotFoundException e) { 174 Log.e(TAG, "intent for (" + action.getTitle() + ") not found:", e); 175 } 176 } else { 177 Log.e(TAG, "null intent for: " + action.getTitle()); 178 } 179 } 180 } 181 182 private ArrayList<Action> getLegalActions() { 183 ArrayList<Action> actions = new ArrayList<Action>(); 184 actions.add(new Action.Builder() 185 .intent(systemIntent(SETTINGS_LEGAL_LICENSE_INTENT_ACTION)) 186 .title(getString(R.string.about_legal_license)) 187 .build()); 188 actions.add(new Action.Builder() 189 .intent(systemIntent(SETTINGS_LEGAL_TERMS_OF_SERVICE)) 190 .title(getString(R.string.about_terms_of_service)) 191 .build()); 192 193 return actions; 194 } 195 196 private ArrayList<Action> getActions() { 197 ArrayList<Action> actions = new ArrayList<Action>(); 198 actions.add(new Action.Builder() 199 .key("update") 200 .title(getString(R.string.about_system_update)) 201 .intent(systemIntent(SETTINGS_UPDATE_SYSTEM)) 202 .build()); 203 actions.add(new Action.Builder() 204 .key("name") 205 .title(getString(R.string.device_name)) 206 .description(DeviceManager.getDeviceName(this)) 207 .intent(new Intent(SETTINGS_DEVICE_NAME_INTENT_ACTION)) 208 .build()); 209 actions.add(new Action.Builder() 210 .key(KEY_REBOOT) 211 .title(getString(R.string.restart_button_label)) 212 .build()); 213 actions.add(new Action.Builder() 214 .key(KEY_LEGAL_INFO) 215 .title(getString(R.string.about_legal_info)) 216 .build()); 217 Intent adsIntent = new Intent(); 218 adsIntent.setPackage(SETTINGS_ADS_ACTIVITY_PACKAGE); 219 adsIntent.setAction(SETTINGS_ADS_ACTIVITY_ACTION); 220 adsIntent.addCategory(Intent.CATEGORY_DEFAULT); 221 List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities(adsIntent, 222 PackageManager.MATCH_DEFAULT_ONLY); 223 if (!resolveInfos.isEmpty()) { 224 // Launch the phone ads id activity. 225 actions.add(new Action.Builder() 226 .key("ads") 227 .title(getString(R.string.about_ads)) 228 .intent(adsIntent) 229 .enabled(true) 230 .build()); 231 } 232 actions.add(new Action.Builder() 233 .key("model") 234 .title(getString(R.string.about_model)) 235 .description(Build.MODEL) 236 .enabled(false) 237 .build()); 238 actions.add(new Action.Builder() 239 .key(KEY_VERSION) 240 .title(getString(R.string.about_version)) 241 .description(Build.VERSION.RELEASE) 242 .enabled(true) 243 .build()); 244 actions.add(new Action.Builder() 245 .key("serial") 246 .title(getString(R.string.about_serial)) 247 .description(Build.SERIAL) 248 .enabled(false) 249 .build()); 250 actions.add(new Action.Builder() 251 .key(KEY_BUILD) 252 .title(getString(R.string.about_build)) 253 .description(Build.DISPLAY) 254 .enabled(true) 255 .build()); 256 return actions; 257 } 258 259 private void displayFragment(Fragment fragment) { 260 getFragmentManager() 261 .beginTransaction() 262 .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) 263 .replace(android.R.id.content, fragment) 264 .addToBackStack(null) 265 .commit(); 266 } 267 268 private void showToast(String toastString) { 269 if (mToast != null) { 270 mToast.cancel(); 271 } 272 mToast = Toast.makeText(this, toastString, Toast.LENGTH_SHORT); 273 mToast.show(); 274 } 275 276 // Returns an Intent for the given action if a system app can handle it, otherwise null. 277 private Intent systemIntent(String action) { 278 final Intent intent = new Intent(action); 279 280 // Limit the intent to an activity that is in the system image. 281 final PackageManager pm = getPackageManager(); 282 final List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0); 283 for (ResolveInfo info : activities) { 284 if ((info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 285 if (info.activityInfo.isEnabled()) { 286 intent.setPackage(info.activityInfo.packageName); 287 return intent; 288 } 289 } 290 } 291 return null; // No system image package found. 292 } 293 } 294