• R/O
  • HTTP
  • SSH
  • HTTPS

提交

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

development


Commit MetaInfo

修訂86ed8b3937f631ba3e8a04d20171dfda25c994c1 (tree)
時間2011-02-02 07:50:47
作者Raphael Moll <ralf@andr...>
CommiterAndroid Git Automerger

Log Message

am ae431044: am 33d8964c: am e3ec8442: am 2fa9bd29: Merge "Revamped CustomLocale for the SDK."

* commit 'ae43104493bfe8271e5b1efc809ae06f8ecea893':

Revamped CustomLocale for the SDK.

Change Summary

差異

--- a/apps/CustomLocale/AndroidManifest.xml
+++ b/apps/CustomLocale/AndroidManifest.xml
@@ -13,25 +13,40 @@
1313 See the License for the specific language governing permissions and
1414 limitations under the License.
1515 -->
16+
1617 <manifest
1718 xmlns:android="http://schemas.android.com/apk/res/android"
1819 android:versionCode="1"
19- android:versionName="1.0" package="com.android.customlocale">
20+ android:versionName="1.0"
21+ package="com.android.customlocale2"
22+ >
23+
24+ <uses-sdk android:minSdkVersion="3" />
25+
26+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
27+ <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
28+
2029 <application
2130 android:icon="@drawable/icon"
22- android:label="@string/app_name">
31+ android:label="@string/app_name" >
32+
2333 <activity
24- android:label="@string/app_name" android:name="CustomLocaleActivity">
34+ android:label="@string/app_name"
35+ android:name="CustomLocaleActivity" >
2536 <intent-filter>
2637 <action android:name="android.intent.action.MAIN" />
2738 <category android:name="android.intent.category.LAUNCHER" />
2839 </intent-filter>
2940 </activity>
41+
3042 <activity
31- android:name="NewLocaleDialog"
32- android:theme="@android:style/Theme.Dialog" />
43+ android:theme="@android:style/Theme.Dialog"
44+ android:name="NewLocaleDialog" />
45+
46+ <receiver android:name="CustomLocaleReceiver" >
47+ <intent-filter>
48+ <action android:name="com.android.intent.action.SET_LOCALE" />
49+ </intent-filter>
50+ </receiver>
3351 </application>
34- <uses-sdk android:minSdkVersion="3" />
35- <uses-permission android:name="android.permission.WRITE_SETTINGS" />
36- <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
3752 </manifest>
--- a/apps/CustomLocale/res/layout/list_item.xml
+++ /dev/null
@@ -1,35 +0,0 @@
1-<?xml version="1.0" encoding="utf-8"?>
2-<!-- Copyright (C) 2009 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-<LinearLayout
17- xmlns:android="http://schemas.android.com/apk/res/android"
18- android:layout_width="match_parent"
19- android:layout_height="wrap_content"
20- android:padding="5dip">
21- <TextView
22- android:id="@+id/locale_code"
23- android:layout_width="match_parent"
24- android:layout_height="wrap_content"
25- android:textAppearance="?android:textAppearanceLarge"
26- android:layout_weight="1"
27- android:text="@string/locale_default" />
28- <TextView
29- xmlns:android="http://schemas.android.com/apk/res/android"
30- android:id="@+id/locale_name"
31- android:layout_width="match_parent"
32- android:layout_height="wrap_content"
33- android:textAppearance="?android:textAppearance"
34- android:layout_weight="1" />
35-</LinearLayout>
\ No newline at end of file
--- a/apps/CustomLocale/res/layout/main.xml
+++ b/apps/CustomLocale/res/layout/main.xml
@@ -17,7 +17,8 @@
1717 xmlns:android="http://schemas.android.com/apk/res/android"
1818 android:orientation="vertical"
1919 android:layout_width="match_parent"
20- android:layout_height="match_parent">
20+ android:layout_height="match_parent"
21+ >
2122 <TextView
2223 android:layout_width="match_parent"
2324 android:layout_height="wrap_content"
@@ -25,13 +26,15 @@
2526 android:text="@string/header_current_locale"
2627 android:textAppearance="@style/TextAppearance.header"
2728 android:gravity="center_horizontal"
28- android:background="@color/header_background" />
29+ android:background="@color/header_background"
30+ />
2931 <TextView
3032 android:id="@+id/current_locale"
3133 android:layout_width="match_parent"
3234 android:layout_height="wrap_content"
3335 android:layout_weight="0"
34- android:padding="5dip" />
36+ android:padding="5dip"
37+ />
3538 <TextView
3639 android:layout_width="match_parent"
3740 android:layout_height="wrap_content"
@@ -39,24 +42,61 @@
3942 android:text="@string/header_locale_list"
4043 android:textAppearance="@style/TextAppearance.header"
4144 android:gravity="center_horizontal"
42- android:background="@color/header_background" />
43- <ListView
44- android:id="@id/android:list"
45+ android:background="@color/header_background"
46+ />
47+
48+ <FrameLayout
4549 android:layout_width="match_parent"
4650 android:layout_height="match_parent"
4751 android:layout_weight="1"
48- android:padding="8dip" />
49- <TextView
50- android:id="@id/android:empty"
51- android:layout_width="match_parent"
52- android:layout_height="match_parent"
53- android:text="@string/no_data_label" />
54- <Button
55- android:id="@+id/new_locale"
52+ >
53+ <ListView
54+ android:id="@id/android:list"
55+ android:layout_width="match_parent"
56+ android:layout_height="match_parent"
57+ android:fastScrollEnabled="true"
58+ android:focusable="true"
59+ android:focusableInTouchMode="true"
60+ android:padding="8dip"
61+ />
62+ <TextView
63+ android:id="@id/android:empty"
64+ android:layout_width="match_parent"
65+ android:layout_height="match_parent"
66+ android:text="@string/no_data_label"
67+ android:gravity="center"
68+ />
69+ </FrameLayout>
70+
71+ <LinearLayout
5672 android:layout_width="match_parent"
5773 android:layout_height="wrap_content"
5874 android:layout_weight="0"
59- android:paddingLeft="8dip"
60- android:paddingRight="8dip"
61- android:text="@string/add_new_locale_button" />
75+ >
76+ <Button
77+ android:id="@+id/select_locale_button"
78+ android:layout_width="match_parent"
79+ android:layout_height="wrap_content"
80+ android:layout_weight="0.9"
81+ android:layout_gravity="center_vertical"
82+ android:text="@string/select_locale_button"
83+ />
84+ <Button
85+ android:id="@+id/add_new_locale_button"
86+ android:layout_width="match_parent"
87+ android:layout_height="wrap_content"
88+ android:layout_weight="1"
89+ android:layout_gravity="center_vertical"
90+ android:text="@string/add_new_locale_button"
91+ />
92+ <Button
93+ android:id="@+id/remove_locale_button"
94+ android:layout_width="match_parent"
95+ android:layout_height="wrap_content"
96+ android:layout_weight="1"
97+ android:layout_marginLeft="5dip"
98+ android:layout_gravity="center_vertical"
99+ android:text="@string/remove_locale_button"
100+ />
101+ </LinearLayout>
62102 </LinearLayout>
--- a/apps/CustomLocale/res/values-fr/strings.xml
+++ b/apps/CustomLocale/res/values-fr/strings.xml
@@ -15,11 +15,34 @@
1515 -->
1616 <resources>
1717 <string name="app_name">Locales Personalisées</string>
18- <string name="add_new_locale_button">Ajouter une nouvelle locale</string>
19- <string name="new_locale_label">Code de la nouvelle locale:</string>
20- <string name="add_button">Ajouter</string>
21- <string name="no_data_label">Aucune locale</string>
18+
19+ <!-- Top labels in CustomLocaleActivity -->
20+
2221 <string name="header_current_locale">Locale courrante</string>
2322 <string name="header_locale_list">Liste des locales</string>
24- <string name="add_select_button">Ajouter et sélectionner</string>
23+ <string name="no_data_label">Aucune locale</string>
24+
25+ <!-- Buttons in CustomLocaleActivity -->
26+
27+ <string name="select_locale_button">Choisir</string>
28+ <string name="select_locale_1s_button">Choisir \'%1$s\'</string>
29+ <string name="add_new_locale_button">Ajouter\u2026</string>
30+ <string name="remove_locale_button">Retirer\u2026</string>
31+
32+ <!-- Toast status in CustomLocaleActivity -->
33+
34+ <string name="removed_custom_locale_1s">Locale supprimée: %1$s</string>
35+ <string name="select_locale_1s">Locale choisie: %1$s</string>
36+ <string name="added_custom_locale_1s">Locale ajoutée: %1$s</string>
37+
38+ <!-- NewLocaleDialog -->
39+
40+ <string name="new_locale_label">Code de la nouvelle locale:</string>
41+ <string name="add_button">Ajouter</string>
42+ <string name="add_select_button">Ajouter et choisir</string>
43+
44+ <string name="confirm_remove_locale_1s">Voulez-vous supprimer la locale personalisée \'%1$s\' ?</string>
45+ <string name="confirm_remove_locale_yes">Oui</string>
46+ <string name="confirm_remove_locale_no">Non</string>
47+
2548 </resources>
--- a/apps/CustomLocale/res/values/strings.xml
+++ b/apps/CustomLocale/res/values/strings.xml
@@ -15,12 +15,37 @@
1515 -->
1616 <resources>
1717 <string name="app_name">Custom Locale</string>
18- <string name="locale_default">ex_EX</string>
19- <string name="add_new_locale_button">Add New Locale</string>
20- <string name="new_locale_label">New locale code:</string>
21- <string name="add_button">Add</string>
22- <string name="no_data_label">No data</string>
18+
19+ <!-- Top labels in CustomLocaleActivity -->
20+
2321 <string name="header_current_locale">Current Locale</string>
2422 <string name="header_locale_list">Locale List</string>
23+ <string name="no_data_label">No data</string>
24+
25+ <!-- Buttons in CustomLocaleActivity -->
26+
27+ <string name="select_locale_button">Select</string>
28+ <string name="select_locale_1s_button">Select \'%1$s\'</string>
29+ <string name="add_new_locale_button">Add New\u2026</string>
30+ <string name="remove_locale_button">Remove\u2026</string>
31+
32+ <!-- Toast status in CustomLocaleActivity -->
33+
34+ <string name="removed_custom_locale_1s">Removed custom locale: %1$s</string>
35+ <string name="select_locale_1s">Select locale: %1$s</string>
36+ <string name="added_custom_locale_1s">Added custom locale: %1$s</string>
37+
38+ <!-- NewLocaleDialog -->
39+
40+ <string name="new_locale_label">New locale code:</string>
41+ <string name="add_button">Add</string>
2542 <string name="add_select_button">Add and Select</string>
43+
44+ <string name="confirm_remove_locale_1s">Do you want to remove the custom locale \'%1$s\'?</string>
45+ <string name="confirm_remove_locale_yes">Yes</string>
46+ <string name="confirm_remove_locale_no">No</string>
47+
48+ <!-- Locale hint in textfield. Not translated -->
49+ <string name="locale_default">ex_EX</string>
50+
2651 </resources>
--- a/apps/CustomLocale/src/com/android/customlocale/CustomLocaleActivity.java
+++ /dev/null
@@ -1,334 +0,0 @@
1-/*
2- * Copyright (C) 2009 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.customlocale;
18-
19-
20-import android.app.ActivityManagerNative;
21-import android.app.IActivityManager;
22-import android.app.ListActivity;
23-import android.content.Intent;
24-import android.content.SharedPreferences;
25-import android.content.res.Configuration;
26-import android.os.Bundle;
27-import android.os.RemoteException;
28-import android.util.Log;
29-import android.view.ContextMenu;
30-import android.view.MenuItem;
31-import android.view.View;
32-import android.view.ContextMenu.ContextMenuInfo;
33-import android.widget.Button;
34-import android.widget.ListAdapter;
35-import android.widget.ListView;
36-import android.widget.SimpleAdapter;
37-import android.widget.TextView;
38-import android.widget.Toast;
39-import android.widget.AdapterView.AdapterContextMenuInfo;
40-
41-import java.util.ArrayList;
42-import java.util.Collections;
43-import java.util.Comparator;
44-import java.util.HashMap;
45-import java.util.Locale;
46-import java.util.Map;
47-
48-/**
49- * Displays the list of system locales as well as maintain a custom list of user
50- * locales. The user can select a locale and apply it or it can create or remove
51- * a custom locale.
52- */
53-public class CustomLocaleActivity extends ListActivity {
54-
55- private static final String CUSTOM_LOCALES_SEP = " ";
56- private static final String CUSTOM_LOCALES = "custom_locales";
57- private static final String KEY_CUSTOM = "custom";
58- private static final String KEY_NAME = "name";
59- private static final String KEY_CODE = "code";
60-
61- private static final String TAG = "LocaleSetup";
62- private static final boolean DEBUG = true;
63-
64- /** Request code returned when the NewLocaleDialog activity finishes. */
65- private static final int UPDATE_LIST = 42;
66- /** Menu item id for applying a locale */
67- private static final int MENU_APPLY = 43;
68- /** Menu item id for removing a custom locale */
69- private static final int MENU_REMOVE = 44;
70-
71- /** List view displaying system and custom locales. */
72- private ListView mListView;
73- /** Textview used to display current locale */
74- private TextView mCurrentLocaleTextView;
75- /** Private shared preferences of this activity. */
76- private SharedPreferences mPrefs;
77-
78- @Override
79- protected void onCreate(Bundle savedInstanceState) {
80- super.onCreate(savedInstanceState);
81- setContentView(R.layout.main);
82-
83- mPrefs = getPreferences(MODE_PRIVATE);
84-
85- Button newLocaleButton = (Button) findViewById(R.id.new_locale);
86-
87- newLocaleButton.setOnClickListener(new View.OnClickListener() {
88- public void onClick(View v) {
89- Intent i = new Intent(CustomLocaleActivity.this, NewLocaleDialog.class);
90- startActivityForResult(i, UPDATE_LIST);
91- }
92- });
93-
94- mListView = (ListView) findViewById(android.R.id.list);
95- mListView.setFocusable(true);
96- mListView.setFocusableInTouchMode(true);
97- mListView.requestFocus();
98- registerForContextMenu(mListView);
99- setupLocaleList();
100-
101- mCurrentLocaleTextView = (TextView) findViewById(R.id.current_locale);
102- displayCurrentLocale();
103- }
104-
105- @SuppressWarnings("unchecked")
106- @Override
107- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
108- super.onActivityResult(requestCode, resultCode, data);
109-
110- if (requestCode == UPDATE_LIST && resultCode == RESULT_OK && data != null) {
111- String locale = data.getExtras().getString(NewLocaleDialog.INTENT_EXTRA_LOCALE);
112- if (locale != null && locale.length() > 0) {
113- // Get current custom locale list
114- String customLocales = mPrefs.getString(CUSTOM_LOCALES, null);
115-
116- // Update
117- if (customLocales == null) {
118- customLocales = locale;
119- } else {
120- customLocales += CUSTOM_LOCALES_SEP + locale;
121- }
122-
123- // Save prefs
124- if (DEBUG) {
125- Log.d(TAG, "add/customLocales: " + customLocales);
126- }
127- mPrefs.edit().putString(CUSTOM_LOCALES, customLocales).commit();
128-
129- Toast.makeText(this, "Added custom locale: " + locale, Toast.LENGTH_SHORT).show();
130-
131- // Update list view
132- setupLocaleList();
133-
134- // Find the item to select it in the list view
135- ListAdapter a = mListView.getAdapter();
136- for (int i = 0; i < a.getCount(); i++) {
137- Object o = a.getItem(i);
138- if (o instanceof Map<?, ?>) {
139- String code = ((Map<String, String>) o).get(KEY_CODE);
140- if (code != null && code.equals(locale)) {
141- mListView.setSelection(i);
142- break;
143- }
144- }
145- }
146-
147- if (data.getExtras().getBoolean(NewLocaleDialog.INTENT_EXTRA_SELECT)) {
148- selectLocale(locale);
149- }
150- }
151- }
152- }
153-
154- private void setupLocaleList() {
155- if (DEBUG) {
156- Log.d(TAG, "Update locate list");
157- }
158-
159- ArrayList<Map<String, String>> data = new ArrayList<Map<String, String>>();
160-
161- // Insert all system locales
162- String[] locales = getAssets().getLocales();
163- for (String locale : locales) {
164- Locale loc = new Locale(locale);
165-
166- Map<String, String> map = new HashMap<String, String>(1);
167- map.put(KEY_CODE, locale);
168- map.put(KEY_NAME, loc.getDisplayName());
169- data.add(map);
170- }
171- locales = null;
172-
173- // Insert all custom locales
174- String customLocales = mPrefs.getString(CUSTOM_LOCALES, "");
175- if (DEBUG) {
176- Log.d(TAG, "customLocales: " + customLocales);
177- }
178- for (String locale : customLocales.split(CUSTOM_LOCALES_SEP)) {
179- if (locale != null && locale.length() > 0) {
180- Locale loc = new Locale(locale);
181-
182- Map<String, String> map = new HashMap<String, String>(1);
183- map.put(KEY_CODE, locale);
184- map.put(KEY_NAME, loc.getDisplayName() + " [Custom]");
185- // the presence of the "custom" key marks it as custom.
186- map.put(KEY_CUSTOM, "");
187- data.add(map);
188- }
189- }
190-
191- // Sort all locales by code
192- Collections.sort(data, new Comparator<Map<String, String>>() {
193- public int compare(Map<String, String> lhs, Map<String, String> rhs) {
194- return lhs.get(KEY_CODE).compareTo(rhs.get(KEY_CODE));
195- }
196- });
197-
198- // Update the list view adapter
199- mListView.setAdapter(new SimpleAdapter(this, data, R.layout.list_item, new String[] {
200- KEY_CODE, KEY_NAME}, new int[] {R.id.locale_code, R.id.locale_name}));
201- }
202-
203- @SuppressWarnings("unchecked")
204- @Override
205- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
206- super.onCreateContextMenu(menu, v, menuInfo);
207-
208- if (menuInfo instanceof AdapterContextMenuInfo) {
209- int position = ((AdapterContextMenuInfo) menuInfo).position;
210- Object o = mListView.getItemAtPosition(position);
211- if (o instanceof Map<?, ?>) {
212- String locale = ((Map<String, String>) o).get(KEY_CODE);
213- String custom = ((Map<String, String>) o).get(KEY_CUSTOM);
214-
215- if (custom == null) {
216- menu.setHeaderTitle("System Locale");
217- menu.add(0, MENU_APPLY, 0, "Apply");
218- } else {
219- menu.setHeaderTitle("Custom Locale");
220- menu.add(0, MENU_APPLY, 0, "Apply");
221- menu.add(0, MENU_REMOVE, 0, "Remove");
222- }
223- }
224- }
225- }
226-
227- @SuppressWarnings("unchecked")
228- @Override
229- public boolean onContextItemSelected(MenuItem item) {
230-
231- String pendingLocale = null;
232- boolean is_custom = false;
233-
234- ContextMenuInfo menuInfo = item.getMenuInfo();
235- if (menuInfo instanceof AdapterContextMenuInfo) {
236- int position = ((AdapterContextMenuInfo) menuInfo).position;
237- Object o = mListView.getItemAtPosition(position);
238- if (o instanceof Map<?, ?>) {
239- pendingLocale = ((Map<String, String>) o).get(KEY_CODE);
240- is_custom = ((Map<String, String>) o).get(KEY_CUSTOM) != null;
241- }
242- }
243-
244- if (pendingLocale == null) {
245- // should never happen
246- return super.onContextItemSelected(item);
247- }
248-
249- if (item.getItemId() == MENU_REMOVE) {
250- // Get current custom locale list
251- String customLocales = mPrefs.getString(CUSTOM_LOCALES, "");
252-
253- if (DEBUG) {
254- Log.d(TAG, "Remove " + pendingLocale + " from custom locales: " + customLocales);
255- }
256-
257- // Update
258- StringBuilder sb = new StringBuilder();
259- for (String locale : customLocales.split(CUSTOM_LOCALES_SEP)) {
260- if (locale != null && locale.length() > 0 && !locale.equals(pendingLocale)) {
261- if (sb.length() > 0) {
262- sb.append(CUSTOM_LOCALES_SEP);
263- }
264- sb.append(locale);
265- }
266- }
267- String newLocales = sb.toString();
268- if (!newLocales.equals(customLocales)) {
269- // Save prefs
270- mPrefs.edit().putString(CUSTOM_LOCALES, customLocales).commit();
271-
272- Toast.makeText(this, "Removed custom locale: " + pendingLocale, Toast.LENGTH_SHORT)
273- .show();
274- }
275-
276- } else if (item.getItemId() == MENU_APPLY) {
277- selectLocale(pendingLocale);
278- }
279-
280- return super.onContextItemSelected(item);
281- }
282-
283- private void selectLocale(String locale) {
284- if (DEBUG) {
285- Log.d(TAG, "Select locale " + locale);
286- }
287-
288- try {
289- IActivityManager am = ActivityManagerNative.getDefault();
290- Configuration config = am.getConfiguration();
291-
292- Locale loc = null;
293-
294- String[] langCountry = locale.split("_");
295- if (langCountry.length == 2) {
296- loc = new Locale(langCountry[0], langCountry[1]);
297- } else {
298- loc = new Locale(locale);
299- }
300-
301- config.locale = loc;
302-
303- // indicate this isn't some passing default - the user wants this
304- // remembered
305- config.userSetLocale = true;
306-
307- am.updateConfiguration(config);
308-
309- Toast.makeText(this, "Select locale: " + locale, Toast.LENGTH_SHORT).show();
310- } catch (RemoteException e) {
311- if (DEBUG) {
312- Log.e(TAG, "Select locale failed", e);
313- }
314- }
315- }
316-
317- private void displayCurrentLocale() {
318- try {
319- IActivityManager am = ActivityManagerNative.getDefault();
320- Configuration config = am.getConfiguration();
321-
322- if (config.locale != null) {
323- String text = String.format("%s - %s",
324- config.locale.toString(),
325- config.locale.getDisplayName());
326- mCurrentLocaleTextView.setText(text);
327- }
328- } catch (RemoteException e) {
329- if (DEBUG) {
330- Log.e(TAG, "get current locale failed", e);
331- }
332- }
333- }
334-}
--- /dev/null
+++ b/apps/CustomLocale/src/com/android/customlocale2/ChangeLocale.java
@@ -0,0 +1,78 @@
1+/*
2+ * Copyright (C) 2011 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.customlocale2;
18+
19+
20+import java.util.Locale;
21+
22+import android.app.ActivityManagerNative;
23+import android.app.IActivityManager;
24+import android.content.res.Configuration;
25+import android.os.RemoteException;
26+import android.util.Log;
27+
28+/**
29+ * Helper class to change the system locale.
30+ */
31+public final class ChangeLocale {
32+
33+ private static final String TAG = ChangeLocale.class.getSimpleName();
34+ private static final boolean DEBUG = true;
35+
36+ /**
37+ * Sets the system locale to the new one specified.
38+ *
39+ * @param locale A locale name in the form "ab_AB". Must not be null or empty.
40+ * @return True if the locale was succesfully changed.
41+ */
42+ public static boolean changeSystemLocale(String locale) {
43+ if (DEBUG) {
44+ Log.d(TAG, "Change locale to: " + locale);
45+ }
46+
47+ try {
48+ IActivityManager am = ActivityManagerNative.getDefault();
49+ Configuration config = am.getConfiguration();
50+
51+ Locale loc = null;
52+
53+ String[] langCountry = locale.split("_");
54+ if (langCountry.length == 2) {
55+ loc = new Locale(langCountry[0], langCountry[1]);
56+ } else {
57+ loc = new Locale(locale);
58+ }
59+
60+ config.locale = loc;
61+
62+ // indicate this isn't some passing default - the user wants this
63+ // remembered
64+ config.userSetLocale = true;
65+
66+ am.updateConfiguration(config);
67+
68+ return true;
69+
70+ } catch (RemoteException e) {
71+ if (DEBUG) {
72+ Log.e(TAG, "Change locale failed", e);
73+ }
74+ }
75+
76+ return false;
77+ }
78+}
--- /dev/null
+++ b/apps/CustomLocale/src/com/android/customlocale2/CustomLocaleActivity.java
@@ -0,0 +1,454 @@
1+/*
2+ * Copyright (C) 2009 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.customlocale2;
18+
19+
20+import java.util.ArrayList;
21+import java.util.Collections;
22+import java.util.Comparator;
23+import java.util.Locale;
24+
25+import android.app.ActivityManagerNative;
26+import android.app.AlertDialog;
27+import android.app.Dialog;
28+import android.app.IActivityManager;
29+import android.app.ListActivity;
30+import android.content.DialogInterface;
31+import android.content.Intent;
32+import android.content.SharedPreferences;
33+import android.content.res.Configuration;
34+import android.os.Bundle;
35+import android.os.RemoteException;
36+import android.util.Log;
37+import android.view.ContextMenu;
38+import android.view.View;
39+import android.view.ContextMenu.ContextMenuInfo;
40+import android.widget.ArrayAdapter;
41+import android.widget.Button;
42+import android.widget.ListAdapter;
43+import android.widget.ListView;
44+import android.widget.TextView;
45+import android.widget.Toast;
46+import android.widget.AdapterView.AdapterContextMenuInfo;
47+
48+/**
49+ * Displays the list of system locales as well as maintain a custom list of user
50+ * locales. The user can select a locale and apply it or it can create or remove
51+ * a custom locale.
52+ */
53+public class CustomLocaleActivity extends ListActivity {
54+
55+ private static final String TAG = "CustomLocale";
56+ private static final boolean DEBUG = true;
57+
58+ private static final int DLG_REMOVE_ID = 0;
59+
60+ private static final String CUSTOM_LOCALES_SEP = " ";
61+ private static final String CUSTOM_LOCALES = "custom_locales";
62+
63+ /** Request code returned when the NewLocaleDialog activity finishes. */
64+ private static final int UPDATE_LIST = 42;
65+ /** Menu item id for applying a locale */
66+ private static final int MENU_APPLY = 43;
67+ /** Menu item id for removing a custom locale */
68+ private static final int MENU_REMOVE = 44;
69+
70+ /** List view displaying system and custom locales. */
71+ private ListView mListView;
72+ /** Textview used to display current locale */
73+ private TextView mCurrentLocaleTextView;
74+ /** Private shared preferences of this activity. */
75+ private SharedPreferences mPrefs;
76+
77+ private Button mRemoveLocaleButton;
78+ private Button mSelectLocaleButton;
79+
80+ @Override
81+ protected void onCreate(Bundle savedInstanceState) {
82+ super.onCreate(savedInstanceState);
83+ setContentView(R.layout.main);
84+
85+ mPrefs = getPreferences(MODE_PRIVATE);
86+
87+ Button addLocaleButton = (Button) findViewById(R.id.add_new_locale_button);
88+ mRemoveLocaleButton = (Button) findViewById(R.id.remove_locale_button);
89+ mSelectLocaleButton = (Button) findViewById(R.id.select_locale_button);
90+
91+ addLocaleButton.setOnClickListener(new View.OnClickListener() {
92+ public void onClick(View v) {
93+ onAddNewLocale();
94+ }
95+ });
96+
97+ mRemoveLocaleButton.setOnClickListener(new View.OnClickListener() {
98+ @Override
99+ public void onClick(View v) {
100+ showDialog(DLG_REMOVE_ID);
101+ }
102+ });
103+
104+ mSelectLocaleButton.setOnClickListener(new View.OnClickListener() {
105+ @Override
106+ public void onClick(View v) {
107+ onSelectLocale();
108+ }
109+ });
110+
111+ mListView = (ListView) findViewById(android.R.id.list);
112+ mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
113+ mListView.setItemsCanFocus(false);
114+ mListView.setFocusable(true);
115+ mListView.setFocusableInTouchMode(true);
116+ mListView.requestFocus();
117+ setupLocaleList();
118+
119+ mCurrentLocaleTextView = (TextView) findViewById(R.id.current_locale);
120+ displayCurrentLocale();
121+ }
122+
123+ @Override
124+ protected void onResume() {
125+ super.onResume();
126+ updateLocaleButtons();
127+ }
128+
129+ @Override
130+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
131+ super.onActivityResult(requestCode, resultCode, data);
132+
133+ if (requestCode == UPDATE_LIST && resultCode == RESULT_OK && data != null) {
134+ String locale = data.getExtras().getString(NewLocaleDialog.INTENT_EXTRA_LOCALE);
135+ if (locale != null && locale.length() > 0) {
136+ // Get current custom locale list
137+ String customLocales = mPrefs.getString(CUSTOM_LOCALES, null);
138+
139+ // Update
140+ if (customLocales == null) {
141+ customLocales = locale;
142+ } else {
143+ customLocales += CUSTOM_LOCALES_SEP + locale;
144+ }
145+
146+ // Save prefs
147+ if (DEBUG) {
148+ Log.d(TAG, "add/customLocales: " + customLocales);
149+ }
150+ mPrefs.edit().putString(CUSTOM_LOCALES, customLocales).commit();
151+
152+ Toast.makeText(this,
153+ getString(R.string.added_custom_locale_1s, locale),
154+ Toast.LENGTH_SHORT)
155+ .show();
156+
157+ // Update list view
158+ setupLocaleList();
159+
160+ // Find the item to select it in the list view
161+ checkLocaleInList(locale);
162+
163+ if (data.getExtras().getBoolean(NewLocaleDialog.INTENT_EXTRA_SELECT)) {
164+ changeSystemLocale(locale);
165+ }
166+ }
167+ }
168+ }
169+
170+ @Override
171+ protected void onListItemClick(ListView l, View v, int position, long id) {
172+ super.onListItemClick(l, v, position, id);
173+ updateLocaleButtons();
174+ }
175+
176+ @Override
177+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
178+ super.onCreateContextMenu(menu, v, menuInfo);
179+
180+ if (menuInfo instanceof AdapterContextMenuInfo) {
181+ int position = ((AdapterContextMenuInfo) menuInfo).position;
182+ Object o = mListView.getItemAtPosition(position);
183+ if (o instanceof LocaleInfo) {
184+ if (((LocaleInfo) o).isCustom()) {
185+ menu.setHeaderTitle("System Locale");
186+ menu.add(0, MENU_APPLY, 0, "Apply");
187+ } else {
188+ menu.setHeaderTitle("Custom Locale");
189+ menu.add(0, MENU_APPLY, 0, "Apply");
190+ menu.add(0, MENU_REMOVE, 0, "Remove");
191+ }
192+ }
193+ }
194+ }
195+
196+ @Override
197+ protected Dialog onCreateDialog(int id) {
198+ if (id == DLG_REMOVE_ID) {
199+ return createRemoveLocaleDialog();
200+ }
201+ return super.onCreateDialog(id);
202+ }
203+
204+ //--- private parts ---
205+
206+ private void setupLocaleList() {
207+ if (DEBUG) {
208+ Log.d(TAG, "Update locate list");
209+ }
210+
211+ ArrayList<LocaleInfo> data = new ArrayList<LocaleInfo>();
212+
213+ // Insert all system locales
214+ String[] locales = getAssets().getLocales();
215+ for (String locale : locales) {
216+ if (locale != null && locale.length() > 0) {
217+ Locale loc = new Locale(locale);
218+ data.add(new LocaleInfo(locale, loc.getDisplayName()));
219+ }
220+ }
221+ locales = null;
222+
223+ // Insert all custom locales
224+ String customLocales = mPrefs.getString(CUSTOM_LOCALES, "");
225+ if (DEBUG) {
226+ Log.d(TAG, "customLocales: " + customLocales);
227+ }
228+ for (String locale : customLocales.split(CUSTOM_LOCALES_SEP)) {
229+ if (locale != null && locale.length() > 0) {
230+ Locale loc = new Locale(locale);
231+ data.add(new LocaleInfo(
232+ locale,
233+ loc.getDisplayName(),
234+ true /*custom*/));
235+ }
236+ }
237+
238+ // Sort all locales by code
239+ Collections.sort(data, new Comparator<LocaleInfo>() {
240+ public int compare(LocaleInfo lhs, LocaleInfo rhs) {
241+ return lhs.getLocale().compareTo(rhs.getLocale());
242+ }
243+ });
244+
245+ // Update the list view adapter
246+ mListView.setAdapter(new ArrayAdapter<LocaleInfo>(
247+ this,
248+ android.R.layout.simple_list_item_single_choice,
249+ data));
250+ updateLocaleButtons();
251+ }
252+
253+ private void changeSystemLocale(String locale) {
254+ if (ChangeLocale.changeSystemLocale(locale)) {
255+ Toast.makeText(this,
256+ getString(R.string.select_locale_1s, locale),
257+ Toast.LENGTH_SHORT)
258+ .show();
259+ }
260+ }
261+
262+ private void displayCurrentLocale() {
263+ try {
264+ IActivityManager am = ActivityManagerNative.getDefault();
265+ Configuration config = am.getConfiguration();
266+
267+ if (config.locale != null) {
268+ String text = String.format("%1$s - %2$s",
269+ config.locale.toString(),
270+ config.locale.getDisplayName());
271+ mCurrentLocaleTextView.setText(text);
272+
273+ checkLocaleInList(config.locale.toString());
274+ }
275+ } catch (RemoteException e) {
276+ if (DEBUG) {
277+ Log.e(TAG, "get current locale failed", e);
278+ }
279+ }
280+ }
281+
282+ /** Find the locale by code to select it in the list view */
283+ private void checkLocaleInList(String locale) {
284+ ListAdapter a = mListView.getAdapter();
285+ for (int i = 0; i < a.getCount(); i++) {
286+ Object o = a.getItem(i);
287+ if (o instanceof LocaleInfo) {
288+ String code = ((LocaleInfo) o).getLocale();
289+ if (code != null && code.equals(locale)) {
290+ mListView.setSelection(i);
291+ mListView.clearChoices();
292+ mListView.setItemChecked(i, true);
293+ updateLocaleButtons();
294+ break;
295+ }
296+ }
297+ }
298+ }
299+
300+ private LocaleInfo getCheckedLocale() {
301+ int pos = mListView.getCheckedItemPosition();
302+ ListAdapter a = mListView.getAdapter();
303+ int n = a.getCount();
304+ if (pos >= 0 && pos < n) {
305+ Object o = a.getItem(pos);
306+ if (o instanceof LocaleInfo) {
307+ return (LocaleInfo) o;
308+ }
309+ }
310+
311+ return null;
312+ }
313+
314+ /** Update the Select/Remove buttons based on the currently checked locale. */
315+ private void updateLocaleButtons() {
316+ LocaleInfo info = getCheckedLocale();
317+ if (info != null) {
318+ // Enable it
319+ mSelectLocaleButton.setEnabled(true);
320+ mSelectLocaleButton.setText(
321+ getString(R.string.select_locale_1s_button, info.getLocale()));
322+
323+ // Enable the remove button only for custom locales and set the tag to the locale
324+ mRemoveLocaleButton.setEnabled(info.isCustom());
325+ } else {
326+ // If nothing is selected, disable the buttons
327+ mSelectLocaleButton.setEnabled(false);
328+ mSelectLocaleButton.setText(R.string.select_locale_button);
329+
330+ mRemoveLocaleButton.setEnabled(false);
331+ }
332+ }
333+
334+ /** Invoked by the button "Add new..." */
335+ private void onAddNewLocale() {
336+ Intent i = new Intent(CustomLocaleActivity.this, NewLocaleDialog.class);
337+ startActivityForResult(i, UPDATE_LIST);
338+ }
339+
340+ /** Invoked by the button Select / mSelectLocaleButton */
341+ private void onSelectLocale() {
342+ LocaleInfo info = getCheckedLocale();
343+ if (info != null) {
344+ changeSystemLocale(info.getLocale());
345+ }
346+ }
347+
348+ /**
349+ * Invoked by the button Remove / mRemoveLocaleButton.
350+ * Creates a dialog to ask for confirmation before actually remove the custom locale.
351+ */
352+ private Dialog createRemoveLocaleDialog() {
353+
354+ LocaleInfo info = getCheckedLocale();
355+ final String localeToRemove = info == null ? "<error>" : info.getLocale();
356+
357+ AlertDialog.Builder b = new AlertDialog.Builder(this);
358+ b.setMessage(getString(R.string.confirm_remove_locale_1s, localeToRemove));
359+ b.setCancelable(false);
360+ b.setPositiveButton(R.string.confirm_remove_locale_yes,
361+ new DialogInterface.OnClickListener() {
362+ @Override
363+ public void onClick(DialogInterface dialog, int which) {
364+ removeCustomLocale(localeToRemove);
365+ dismissDialog(DLG_REMOVE_ID);
366+ }
367+ });
368+ b.setNegativeButton(R.string.confirm_remove_locale_no,
369+ new DialogInterface.OnClickListener() {
370+ @Override
371+ public void onClick(DialogInterface dialog, int which) {
372+ dismissDialog(DLG_REMOVE_ID);
373+ }
374+ });
375+
376+ return b.create();
377+ }
378+
379+ private void removeCustomLocale(String localeToRemove) {
380+ // Get current custom locale list
381+ String oldLocales = mPrefs.getString(CUSTOM_LOCALES, "");
382+
383+ if (DEBUG) {
384+ Log.d(TAG, "Remove " + localeToRemove + " from custom locales: " + oldLocales);
385+ }
386+
387+ // Update
388+ StringBuilder sb = new StringBuilder();
389+ for (String locale : oldLocales.split(CUSTOM_LOCALES_SEP)) {
390+ if (locale != null && locale.length() > 0 && !locale.equals(localeToRemove)) {
391+ if (sb.length() > 0) {
392+ sb.append(CUSTOM_LOCALES_SEP);
393+ }
394+ sb.append(locale);
395+ }
396+ }
397+
398+ String newLocales = sb.toString();
399+ if (!newLocales.equals(oldLocales)) {
400+ // Save prefs
401+ boolean ok = mPrefs.edit().putString(CUSTOM_LOCALES, newLocales).commit();
402+ if (DEBUG) {
403+ Log.d(TAG, "Prefs commit:" + Boolean.toString(ok) + ". Saved: " + newLocales);
404+ }
405+
406+ Toast.makeText(this,
407+ getString(R.string.removed_custom_locale_1s, localeToRemove),
408+ Toast.LENGTH_SHORT)
409+ .show();
410+
411+ // Update list view
412+ setupLocaleList();
413+ }
414+ }
415+
416+ /**
417+ * Immutable structure that holds the information displayed by a list view item.
418+ */
419+ private static class LocaleInfo {
420+ private final String mLocale;
421+ private final String mDisplayName;
422+ private final boolean mIsCustom;
423+
424+ public LocaleInfo(String locale, String displayName, boolean isCustom) {
425+ mLocale = locale;
426+ mDisplayName = displayName;
427+ mIsCustom = isCustom;
428+ }
429+
430+ public LocaleInfo(String locale, String displayName) {
431+ this(locale, displayName, false /*custom*/);
432+ }
433+
434+ public String getLocale() {
435+ return mLocale;
436+ }
437+
438+ public boolean isCustom() {
439+ return mIsCustom;
440+ }
441+
442+ @Override
443+ public String toString() {
444+ StringBuilder sb = new StringBuilder();
445+ sb.append(mLocale)
446+ .append(" - ")
447+ .append(mDisplayName);
448+ if (mIsCustom) {
449+ sb.append(" [Custom]");
450+ }
451+ return sb.toString();
452+ }
453+ }
454+}
--- /dev/null
+++ b/apps/CustomLocale/src/com/android/customlocale2/CustomLocaleReceiver.java
@@ -0,0 +1,82 @@
1+/*
2+ * Copyright (C) 2011 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.customlocale2;
18+
19+import android.app.Activity;
20+import android.content.BroadcastReceiver;
21+import android.content.Context;
22+import android.content.Intent;
23+import android.util.Log;
24+
25+//-----------------------------------------------
26+
27+/**
28+ * Broadcast receiver that can change the system's locale.
29+ * <p/>
30+ * This allows an external script such as an automated testing framework
31+ * to easily trigger a locale change on an emulator as such:
32+ * <pre>
33+ * $ adb shell am broadcast -a com.android.intent.action.SET_LOCALE \
34+ * --es com.android.intent.extra.LOCALE en_US
35+ * </pre>
36+ */
37+public class CustomLocaleReceiver extends BroadcastReceiver {
38+
39+ private static final String TAG = CustomLocaleReceiver.class.getSimpleName();
40+ private static final boolean DEBUG = true;
41+
42+ /** Intent action that triggers this receiver. */
43+ public static final String ACTION_SET_LOCALE = "com.android.intent.action.SET_LOCALE";
44+ /** An extra String that specifies the locale to set, in the form "en_US". */
45+ public static final String EXTRA_LOCALE = "com.android.intent.extra.LOCALE";
46+
47+ @Override
48+ public void onReceive(Context context, Intent intent) {
49+ setResult(Activity.RESULT_CANCELED, null, null);
50+ if (intent == null || ! ACTION_SET_LOCALE.equals(intent.getAction())) {
51+ if (DEBUG) {
52+ Log.d(TAG, "Invalid intent: " + (intent == null ? "null" : intent.toString()));
53+ }
54+ return;
55+ }
56+
57+ String locale = intent.getStringExtra(EXTRA_LOCALE);
58+
59+ // Enforce the locale string is either in the form "ab" or "ab_cd"
60+ boolean is_ok = locale != null;
61+ is_ok = is_ok && (locale.length() == 2 || locale.length() == 5);
62+ if (is_ok && locale.length() >= 2) {
63+ is_ok = Character.isLetter(locale.charAt(0)) &&
64+ Character.isLetter(locale.charAt(1));
65+ }
66+ if (is_ok && locale.length() == 5) {
67+ is_ok = locale.charAt(2) == '_' &&
68+ Character.isLetter(locale.charAt(3)) &&
69+ Character.isLetter(locale.charAt(4));
70+ }
71+
72+ if (!is_ok && DEBUG) {
73+ Log.e(TAG, "Invalid locale: expected ab_CD but got " + locale);
74+ } else if (is_ok) {
75+ ChangeLocale.changeSystemLocale(locale);
76+ setResult(Activity.RESULT_OK, locale, null);
77+ }
78+ }
79+
80+}
81+
82+
--- a/apps/CustomLocale/src/com/android/customlocale/NewLocaleDialog.java
+++ b/apps/CustomLocale/src/com/android/customlocale2/NewLocaleDialog.java
@@ -14,14 +14,12 @@
1414 * limitations under the License.
1515 */
1616
17-package com.android.customlocale;
17+package com.android.customlocale2;
1818
1919 import android.app.Activity;
2020 import android.content.Intent;
2121 import android.os.Bundle;
22-import android.text.TextUtils;
2322 import android.util.Log;
24-import android.view.KeyEvent;
2523 import android.view.View;
2624 import android.widget.Button;
2725 import android.widget.EditText;
@@ -41,7 +39,6 @@ public class NewLocaleDialog extends Activity implements View.OnClickListener {
4139 private Button mButtonAdd;
4240 private Button mButtonAddSelect;
4341 private EditText mEditText;
44- private boolean mWasEmpty;
4542
4643 @Override
4744 protected void onCreate(Bundle savedInstanceState) {
@@ -50,7 +47,6 @@ public class NewLocaleDialog extends Activity implements View.OnClickListener {
5047 setContentView(R.layout.new_locale);
5148
5249 mEditText = (EditText) findViewById(R.id.value);
53- mWasEmpty = true;
5450
5551 mButtonAdd = (Button) findViewById(R.id.add);
5652 mButtonAdd.setOnClickListener(this);
@@ -62,7 +58,7 @@ public class NewLocaleDialog extends Activity implements View.OnClickListener {
6258 public void onClick(View v) {
6359 String locale = mEditText.getText().toString();
6460 boolean select = v == mButtonAddSelect;
65-
61+
6662 if (DEBUG) {
6763 Log.d(TAG, "New Locale: " + locale + (select ? " + select" : ""));
6864 }