Loading java-overridable/src/com/android/inputmethod/latin/utils/LoginAccountUtils.java 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.latin.utils; import android.content.Context; import javax.annotation.Nonnull; /** * Utility class for retrieving accounts that may be used for login. */ public class LoginAccountUtils { private LoginAccountUtils() { // This utility class is not publicly instantiable. } /** * Get the accounts available for login. * * @return an array of accounts. Empty (never null) if no accounts are available for login. */ @Nonnull public static String[] getAccountsForLogin(final Context context) { return new String[0]; } } java/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -158,5 +158,9 @@ <action android:name="android.intent.action.MAIN"/> </intent-filter> </activity> <!-- Unexported activity used for tests. --> <activity android:name=".settings.TestFragmentActivity" android:exported="false" /> </application> </manifest> java/res/values/strings.xml +8 −2 Original line number Diff line number Diff line Loading @@ -181,14 +181,20 @@ <!-- Title of the preference item for switching accounts [CHAR LIMIT=30] --> <string name="switch_accounts">Switch accounts</string> <!-- Summary of the preference item for switching accounts when no accounts are selected [CHAR LIMIT=65] --> <string name="no_accounts_selected">No accounts selected</string> <!-- Summary of the preference item for switching accounts when an account is selected [CHAR LIMIT=65] --> <string name="account_selected">Currently using <xliff:g id="EMAIL_ADDRESS" example="someone@example.com">%1$s</xliff:g></string> <!-- Positive text for selecting an account --> <string name="account_select_ok">OK</string> <!-- Negative text for selecting an account --> <string name="account_select_cancel">Cancel</string> <!-- Text for signing out of an account --> <string name="account_select_sign_out">Sign out</string> <!-- Title of the account picker dialog for selecting an account [CHAR LIMIT=40] --> <string name="account_select_title">Select an account to use</string> <!-- Description for English (UK) keyboard subtype [CHAR LIMIT=25] (UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT. --> Loading java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java +117 −6 Original line number Diff line number Diff line Loading @@ -16,25 +16,41 @@ package com.android.inputmethod.latin.settings; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.text.TextUtils; import android.widget.ListView; import android.widget.Toast; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.define.ProductionFlags; import com.android.inputmethod.latin.utils.LoginAccountUtils; import javax.annotation.Nullable; /** * "Accounts & Privacy" settings sub screen. * * This settings sub screen handles the following preferences: * - TODO: Account selection/management for IME * - TODO: Sync preferences * - TODO: Privacy preferences * <li> Account selection/management for IME * <li> TODO: Sync preferences * <li> TODO: Privacy preferences */ public final class AccountsSettingsFragment extends SubScreenFragment { static final String PREF_ACCCOUNT_SWITCHER = "account_switcher"; private final DialogInterface.OnClickListener mAccountSelectedListener = new AccountSelectedListener(); private final DialogInterface.OnClickListener mAccountSignedOutListener = new AccountSignedOutListener(); @Override public void onCreate(final Bundle icicle) { super.onCreate(icicle); Loading Loading @@ -74,9 +90,104 @@ public final class AccountsSettingsFragment extends SubScreenFragment { } private void refreshAccountSelection() { // TODO: Fetch the currently selected account. // Set the summary for the account preference. // Depending on the account selection, enable/disable preferences that final String currentAccount = getCurrentlySelectedAccount(); final Preference accountSwitcher = findPreference(PREF_ACCCOUNT_SWITCHER); if (currentAccount == null) { // No account is currently selected. accountSwitcher.setSummary(getString(R.string.no_accounts_selected)); } else { // Set the currently selected account. accountSwitcher.setSummary(getString(R.string.account_selected, currentAccount)); } final Context context = getActivity(); final String[] accountsForLogin = LoginAccountUtils.getAccountsForLogin(context); accountSwitcher.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { if (accountsForLogin.length == 0) { // TODO: Handle account addition. Toast.makeText(getActivity(), getString(R.string.account_select_cancel), Toast.LENGTH_SHORT).show(); } else { createAccountPicker(accountsForLogin, currentAccount).show(); } return true; } }); // TODO: Depending on the account selection, enable/disable preferences that // depend on an account. } @Nullable private String getCurrentlySelectedAccount() { return getSharedPreferences().getString(Settings.PREF_ACCOUNT_NAME, null); } /** * Creates an account picker dialog showing the given accounts in a list and selecting * the selected account by default. * The list of accounts must not be null/empty. * * Package-private for testing. */ AlertDialog createAccountPicker(final String[] accounts, final String selectedAccount) { if (accounts == null || accounts.length == 0) { throw new IllegalArgumentException("List of accounts must not be empty"); } // See if the currently selected account is in the list. // If it is, the entry is selected, and a sign-out button is provided. // If it isn't, select the 0th account by default which will get picked up // if the user presses OK. int index = 0; boolean isSignedIn = false; for (int i = 0; i < accounts.length; i++) { if (TextUtils.equals(accounts[i], selectedAccount)) { index = i; isSignedIn = true; break; } } final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) .setTitle(R.string.account_select_title) .setSingleChoiceItems(accounts, index, null) .setPositiveButton(R.string.account_select_ok, mAccountSelectedListener) .setNegativeButton(R.string.account_select_cancel, null); if (isSignedIn) { builder.setNeutralButton(R.string.account_select_sign_out, mAccountSignedOutListener); } return builder.create(); } /** * Listener for an account being selected from the picker. * Persists the account to shared preferences. */ class AccountSelectedListener implements DialogInterface.OnClickListener { @Override public void onClick(DialogInterface dialog, int which) { final ListView lv = ((AlertDialog)dialog).getListView(); final Object selectedItem = lv.getItemAtPosition(lv.getCheckedItemPosition()); getSharedPreferences() .edit() .putString(Settings.PREF_ACCOUNT_NAME, (String) selectedItem) .apply(); } } /** * Listener for sign-out being initiated from from the picker. * Removed the account from shared preferences. */ class AccountSignedOutListener implements DialogInterface.OnClickListener { @Override public void onClick(DialogInterface dialog, int which) { getSharedPreferences() .edit() .remove(Settings.PREF_ACCOUNT_NAME) .apply(); } } } java/src/com/android/inputmethod/latin/settings/TestFragmentActivity.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.latin.settings; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.content.Intent; import android.os.Bundle; /** * Test activity to use when testing preference fragments. <br/> * Usage: <br/> * Create an ActivityInstrumentationTestCase2 for this activity * and call setIntent() with an intent that specifies the fragment to load in the activity. * The fragment can then be obtained from this activity and used for testing/verification. */ public final class TestFragmentActivity extends Activity { /** * The fragment name that should be loaded when starting this activity. * This must be specified when starting this activity, as this activity is only * meant to test fragments from instrumentation tests. */ public static final String EXTRA_SHOW_FRAGMENT = "show_fragment"; public Fragment mFragment; @Override protected void onCreate(final Bundle savedState) { super.onCreate(savedState); final Intent intent = getIntent(); final String fragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT); if (fragmentName == null) { throw new IllegalArgumentException("No fragment name specified for testing"); } mFragment = Fragment.instantiate(this, fragmentName); FragmentManager fragmentManager = getFragmentManager(); fragmentManager.beginTransaction().add(mFragment, fragmentName).commit(); } } Loading
java-overridable/src/com/android/inputmethod/latin/utils/LoginAccountUtils.java 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.latin.utils; import android.content.Context; import javax.annotation.Nonnull; /** * Utility class for retrieving accounts that may be used for login. */ public class LoginAccountUtils { private LoginAccountUtils() { // This utility class is not publicly instantiable. } /** * Get the accounts available for login. * * @return an array of accounts. Empty (never null) if no accounts are available for login. */ @Nonnull public static String[] getAccountsForLogin(final Context context) { return new String[0]; } }
java/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -158,5 +158,9 @@ <action android:name="android.intent.action.MAIN"/> </intent-filter> </activity> <!-- Unexported activity used for tests. --> <activity android:name=".settings.TestFragmentActivity" android:exported="false" /> </application> </manifest>
java/res/values/strings.xml +8 −2 Original line number Diff line number Diff line Loading @@ -181,14 +181,20 @@ <!-- Title of the preference item for switching accounts [CHAR LIMIT=30] --> <string name="switch_accounts">Switch accounts</string> <!-- Summary of the preference item for switching accounts when no accounts are selected [CHAR LIMIT=65] --> <string name="no_accounts_selected">No accounts selected</string> <!-- Summary of the preference item for switching accounts when an account is selected [CHAR LIMIT=65] --> <string name="account_selected">Currently using <xliff:g id="EMAIL_ADDRESS" example="someone@example.com">%1$s</xliff:g></string> <!-- Positive text for selecting an account --> <string name="account_select_ok">OK</string> <!-- Negative text for selecting an account --> <string name="account_select_cancel">Cancel</string> <!-- Text for signing out of an account --> <string name="account_select_sign_out">Sign out</string> <!-- Title of the account picker dialog for selecting an account [CHAR LIMIT=40] --> <string name="account_select_title">Select an account to use</string> <!-- Description for English (UK) keyboard subtype [CHAR LIMIT=25] (UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT. --> Loading
java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java +117 −6 Original line number Diff line number Diff line Loading @@ -16,25 +16,41 @@ package com.android.inputmethod.latin.settings; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.text.TextUtils; import android.widget.ListView; import android.widget.Toast; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.define.ProductionFlags; import com.android.inputmethod.latin.utils.LoginAccountUtils; import javax.annotation.Nullable; /** * "Accounts & Privacy" settings sub screen. * * This settings sub screen handles the following preferences: * - TODO: Account selection/management for IME * - TODO: Sync preferences * - TODO: Privacy preferences * <li> Account selection/management for IME * <li> TODO: Sync preferences * <li> TODO: Privacy preferences */ public final class AccountsSettingsFragment extends SubScreenFragment { static final String PREF_ACCCOUNT_SWITCHER = "account_switcher"; private final DialogInterface.OnClickListener mAccountSelectedListener = new AccountSelectedListener(); private final DialogInterface.OnClickListener mAccountSignedOutListener = new AccountSignedOutListener(); @Override public void onCreate(final Bundle icicle) { super.onCreate(icicle); Loading Loading @@ -74,9 +90,104 @@ public final class AccountsSettingsFragment extends SubScreenFragment { } private void refreshAccountSelection() { // TODO: Fetch the currently selected account. // Set the summary for the account preference. // Depending on the account selection, enable/disable preferences that final String currentAccount = getCurrentlySelectedAccount(); final Preference accountSwitcher = findPreference(PREF_ACCCOUNT_SWITCHER); if (currentAccount == null) { // No account is currently selected. accountSwitcher.setSummary(getString(R.string.no_accounts_selected)); } else { // Set the currently selected account. accountSwitcher.setSummary(getString(R.string.account_selected, currentAccount)); } final Context context = getActivity(); final String[] accountsForLogin = LoginAccountUtils.getAccountsForLogin(context); accountSwitcher.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { if (accountsForLogin.length == 0) { // TODO: Handle account addition. Toast.makeText(getActivity(), getString(R.string.account_select_cancel), Toast.LENGTH_SHORT).show(); } else { createAccountPicker(accountsForLogin, currentAccount).show(); } return true; } }); // TODO: Depending on the account selection, enable/disable preferences that // depend on an account. } @Nullable private String getCurrentlySelectedAccount() { return getSharedPreferences().getString(Settings.PREF_ACCOUNT_NAME, null); } /** * Creates an account picker dialog showing the given accounts in a list and selecting * the selected account by default. * The list of accounts must not be null/empty. * * Package-private for testing. */ AlertDialog createAccountPicker(final String[] accounts, final String selectedAccount) { if (accounts == null || accounts.length == 0) { throw new IllegalArgumentException("List of accounts must not be empty"); } // See if the currently selected account is in the list. // If it is, the entry is selected, and a sign-out button is provided. // If it isn't, select the 0th account by default which will get picked up // if the user presses OK. int index = 0; boolean isSignedIn = false; for (int i = 0; i < accounts.length; i++) { if (TextUtils.equals(accounts[i], selectedAccount)) { index = i; isSignedIn = true; break; } } final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) .setTitle(R.string.account_select_title) .setSingleChoiceItems(accounts, index, null) .setPositiveButton(R.string.account_select_ok, mAccountSelectedListener) .setNegativeButton(R.string.account_select_cancel, null); if (isSignedIn) { builder.setNeutralButton(R.string.account_select_sign_out, mAccountSignedOutListener); } return builder.create(); } /** * Listener for an account being selected from the picker. * Persists the account to shared preferences. */ class AccountSelectedListener implements DialogInterface.OnClickListener { @Override public void onClick(DialogInterface dialog, int which) { final ListView lv = ((AlertDialog)dialog).getListView(); final Object selectedItem = lv.getItemAtPosition(lv.getCheckedItemPosition()); getSharedPreferences() .edit() .putString(Settings.PREF_ACCOUNT_NAME, (String) selectedItem) .apply(); } } /** * Listener for sign-out being initiated from from the picker. * Removed the account from shared preferences. */ class AccountSignedOutListener implements DialogInterface.OnClickListener { @Override public void onClick(DialogInterface dialog, int which) { getSharedPreferences() .edit() .remove(Settings.PREF_ACCOUNT_NAME) .apply(); } } }
java/src/com/android/inputmethod/latin/settings/TestFragmentActivity.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.latin.settings; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.content.Intent; import android.os.Bundle; /** * Test activity to use when testing preference fragments. <br/> * Usage: <br/> * Create an ActivityInstrumentationTestCase2 for this activity * and call setIntent() with an intent that specifies the fragment to load in the activity. * The fragment can then be obtained from this activity and used for testing/verification. */ public final class TestFragmentActivity extends Activity { /** * The fragment name that should be loaded when starting this activity. * This must be specified when starting this activity, as this activity is only * meant to test fragments from instrumentation tests. */ public static final String EXTRA_SHOW_FRAGMENT = "show_fragment"; public Fragment mFragment; @Override protected void onCreate(final Bundle savedState) { super.onCreate(savedState); final Intent intent = getIntent(); final String fragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT); if (fragmentName == null) { throw new IllegalArgumentException("No fragment name specified for testing"); } mFragment = Fragment.instantiate(this, fragmentName); FragmentManager fragmentManager = getFragmentManager(); fragmentManager.beginTransaction().add(mFragment, fragmentName).commit(); } }