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