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
17package com.android.email.activity.setup;
18
19import android.app.ActionBar;
20import android.app.Fragment;
21import android.content.Intent;
22import android.net.Uri;
23import android.os.Bundle;
24import android.support.annotation.NonNull;
25import android.view.KeyEvent;
26import android.view.Menu;
27import android.view.MenuItem;
28
29import com.android.email.R;
30import com.android.emailcommon.utility.IntentUtilities;
31import com.android.mail.providers.UIProvider.EditSettingsExtras;
32import com.android.mail.ui.settings.MailPreferenceActivity;
33import com.android.mail.utils.Utils;
34
35import 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 */
46public 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