1 /* 2 * Copyright (C) 2010 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.email.activity.setup; 18 19 import android.app.ActionBar; 20 import android.app.Fragment; 21 import android.content.Intent; 22 import android.net.Uri; 23 import android.os.Bundle; 24 import android.support.annotation.NonNull; 25 import android.view.KeyEvent; 26 import android.view.Menu; 27 import android.view.MenuItem; 28 29 import com.android.email.R; 30 import com.android.email.setup.AuthenticatorSetupIntentHelper; 31 import com.android.emailcommon.utility.IntentUtilities; 32 import com.android.mail.providers.UIProvider.EditSettingsExtras; 33 import com.android.mail.ui.settings.MailPreferenceActivity; 34 import com.android.mail.utils.Utils; 35 36 import java.util.List; 37 38 /** 39 * Handles account preferences, using multi-pane arrangement when possible. 40 * 41 * This activity uses the following fragments: 42 * AccountSettingsFragment 43 * GeneralPreferences 44 * DebugFragment 45 * 46 */ 47 public class EmailPreferenceActivity extends MailPreferenceActivity { 48 /* 49 * Intent to open account settings for account=1 50 adb shell am start -a android.intent.action.EDIT \ 51 -d '"content://ui.email.android.com/settings?ACCOUNT_ID=1"' 52 */ 53 54 // Intent extras for our internal activity launch 55 private static final String EXTRA_ENABLE_DEBUG = "AccountSettings.enable_debug"; 56 // STOPSHIP: Do not ship with the debug menu allowed. 57 private static final boolean DEBUG_MENU_ALLOWED = false; 58 59 // Intent extras for launch directly from system account manager 60 // NOTE: This string must match the one in res/xml/account_preferences.xml 61 private static String INTENT_ACCOUNT_MANAGER_ENTRY; 62 63 // Key codes used to open a debug settings fragment. 64 private static final int[] SECRET_KEY_CODES = { 65 KeyEvent.KEYCODE_D, KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_U, 66 KeyEvent.KEYCODE_G 67 }; 68 private int mSecretKeyCodeIndex = 0; 69 70 // When the user taps "Email Preferences" 10 times in a row, we'll enable the debug settings. 71 private int mNumGeneralHeaderClicked = 0; 72 73 private boolean mShowDebugMenu; 74 private Uri mFeedbackUri; 75 private MenuItem mFeedbackMenuItem; 76 77 @Override 78 public Intent getIntent() { 79 final Intent intent = super.getIntent(); 80 final long accountId = IntentUtilities.getAccountIdFromIntent(intent); 81 if (accountId < 0) { 82 return intent; 83 } 84 Intent modIntent = new Intent(intent); 85 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, AccountSettingsFragment.class.getCanonicalName()); 86 modIntent.putExtra( 87 EXTRA_SHOW_FRAGMENT_ARGUMENTS, 88 AccountSettingsFragment.buildArguments( 89 IntentUtilities.getAccountNameFromIntent(intent))); 90 modIntent.putExtra(EXTRA_NO_HEADERS, true); 91 return modIntent; 92 } 93 94 @Override 95 public void onCreate(Bundle savedInstanceState) { 96 super.onCreate(savedInstanceState); 97 98 final Intent i = getIntent(); 99 if (savedInstanceState == null) { 100 // If we are not restarting from a previous instance, we need to 101 // figure out the initial prefs to show. (Otherwise, we want to 102 // continue showing whatever the user last selected.) 103 if (INTENT_ACCOUNT_MANAGER_ENTRY == null) { 104 INTENT_ACCOUNT_MANAGER_ENTRY = getString(R.string.intent_account_manager_entry); 105 } 106 if (INTENT_ACCOUNT_MANAGER_ENTRY.equals(i.getAction())) { 107 // This case occurs if we're changing account settings from Settings -> Accounts. 108 // We get an account object in the intent, but it's not actually useful to us since 109 // it's always just the first account of that type. The user can't specify which 110 // account they wish to view from within the settings UI, so just dump them at the 111 // main screen. 112 // android.accounts.Account acct = i.getParcelableExtra("account"); 113 } else if (i.hasExtra(EditSettingsExtras.EXTRA_FOLDER)) { 114 throw new IllegalArgumentException("EXTRA_FOLDER is no longer supported"); 115 } else { 116 // Otherwise, we're called from within the Email app and look for our extras 117 final long accountId = IntentUtilities.getAccountIdFromIntent(i); 118 if (accountId != -1) { 119 final Bundle args = AccountSettingsFragment.buildArguments(accountId); 120 startPreferencePanel(AccountSettingsFragment.class.getName(), args, 121 0, null, null, 0); 122 } 123 } 124 } 125 mShowDebugMenu = i.getBooleanExtra(EXTRA_ENABLE_DEBUG, false); 126 127 final ActionBar actionBar = getActionBar(); 128 if (actionBar != null) { 129 actionBar.setDisplayOptions( 130 ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP); 131 } 132 133 mFeedbackUri = Utils.getValidUri(getString(R.string.email_feedback_uri)); 134 } 135 136 /** 137 * Listen for secret sequence and, if heard, enable debug menu 138 */ 139 @Override 140 public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { 141 if (event.getKeyCode() == SECRET_KEY_CODES[mSecretKeyCodeIndex]) { 142 mSecretKeyCodeIndex++; 143 if (mSecretKeyCodeIndex == SECRET_KEY_CODES.length) { 144 mSecretKeyCodeIndex = 0; 145 enableDebugMenu(); 146 } 147 } else { 148 mSecretKeyCodeIndex = 0; 149 } 150 return super.onKeyDown(keyCode, event); 151 } 152 153 @Override 154 public boolean onCreateOptionsMenu(Menu menu) { 155 super.onCreateOptionsMenu(menu); 156 getMenuInflater().inflate(R.menu.settings_menu, menu); 157 158 mFeedbackMenuItem = menu.findItem(R.id.feedback_menu_item); 159 return true; 160 } 161 162 @Override 163 public boolean onPrepareOptionsMenu(Menu menu) { 164 super.onPrepareOptionsMenu(menu); 165 166 if (mFeedbackMenuItem != null) { 167 // We only want to enable the feedback menu item, if there is a valid feedback uri 168 mFeedbackMenuItem.setVisible(!Uri.EMPTY.equals(mFeedbackUri)); 169 } 170 return true; 171 } 172 173 174 @Override 175 public boolean onOptionsItemSelected(MenuItem item) { 176 switch (item.getItemId()) { 177 case android.R.id.home: 178 // The app icon on the action bar is pressed. Just emulate a back press. 179 // TODO: this should navigate to the main screen, even if a sub-setting is open. 180 // But we shouldn't just finish(), as we want to show "discard changes?" dialog 181 // when necessary. 182 onBackPressed(); 183 break; 184 case R.id.feedback_menu_item: 185 Utils.sendFeedback(this, mFeedbackUri, false /* reportingProblem */); 186 break; 187 default: 188 return super.onOptionsItemSelected(item); 189 } 190 return true; 191 } 192 193 @Override 194 public boolean isValidFragment(String fragmentName) { 195 // This activity is not exported, so we can allow any fragment 196 return true; 197 } 198 199 private void enableDebugMenu() { 200 mShowDebugMenu = true; 201 invalidateHeaders(); 202 } 203 204 private void onAddNewAccount() { 205 final Intent setupIntent = AuthenticatorSetupIntentHelper.actionNewAccountIntent(this); 206 startActivity(setupIntent); 207 } 208 209 @Override 210 public void onBuildExtraHeaders(List<Header> target) { 211 super.onBuildExtraHeaders(target); 212 213 loadHeadersFromResource(R.xml.email_extra_preference_headers, target); 214 215 // if debug header is enabled, show it 216 if (DEBUG_MENU_ALLOWED) { 217 if (mShowDebugMenu) { 218 // setup lightweight header for debugging 219 final Header debugHeader = new Header(); 220 debugHeader.title = getText(R.string.debug_title); 221 debugHeader.summary = null; 222 debugHeader.iconRes = 0; 223 debugHeader.fragment = DebugFragment.class.getCanonicalName(); 224 debugHeader.fragmentArguments = null; 225 target.add(debugHeader); 226 } 227 } 228 } 229 230 /** 231 * Called when the user selects an item in the header list. Handles save-data cases as needed 232 * 233 * @param header The header that was selected. 234 * @param position The header's position in the list. 235 */ 236 @Override 237 public void onHeaderClick(@NonNull Header header, int position) { 238 // Secret keys: Click 10x to enable debug settings 239 if (position == 0) { 240 mNumGeneralHeaderClicked++; 241 if (mNumGeneralHeaderClicked == 10) { 242 enableDebugMenu(); 243 } 244 } else { 245 mNumGeneralHeaderClicked = 0; 246 } 247 if (header.id == R.id.add_account_header) { 248 onAddNewAccount(); 249 return; 250 } 251 252 // Process header click normally 253 super.onHeaderClick(header, position); 254 } 255 256 @Override 257 public void onAttachFragment(Fragment f) { 258 super.onAttachFragment(f); 259 // When we're changing fragments, enable/disable the add account button 260 invalidateOptionsMenu(); 261 } 262 } 263