From 105925376f8d0f6b318c9938c7b83ef7fef094da Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 18 Mar 2009 17:39:46 -0700 Subject: [PATCH] auto import from //branches/cupcake_rel/...@140373 --- api/current.xml | 414 +++++++++++-- cmds/pm/src/com/android/commands/pm/Pm.java | 13 +- core/java/android/app/ActivityThread.java | 17 +- core/java/android/app/ApplicationContext.java | 29 +- core/java/android/app/LauncherActivity.java | 4 + core/java/android/app/Service.java | 4 +- .../android/appwidget/AppWidgetManager.java | 17 + .../android/bluetooth/BluetoothDevice.java | 50 +- .../android/bluetooth/BluetoothIntent.java | 14 +- .../android/bluetooth/IBluetoothDevice.aidl | 5 +- .../bluetooth/IBluetoothDeviceCallback.aidl | 2 - core/java/android/bluetooth/ScoSocket.java | 20 +- .../android/content/BroadcastReceiver.java | 8 +- core/java/android/content/Intent.java | 85 ++- .../android/content/pm/PackageManager.java | 8 + core/java/android/emoji/EmojiFactory.java | 16 + .../InputMethodService.java | 244 ++++++-- .../inputmethodservice/SoftInputWindow.java | 12 - core/java/android/os/BatteryStats.java | 109 +++- core/java/android/os/Hardware.java | 37 +- core/java/android/os/IHardwareService.aidl | 12 +- core/java/android/os/Power.java | 28 - core/java/android/os/RemoteCallbackList.java | 2 +- core/java/android/provider/Calendar.java | 5 + core/java/android/provider/CallLog.java | 11 +- core/java/android/provider/Contacts.java | 19 +- .../android/server/BluetoothA2dpService.java | 33 +- .../server/BluetoothDeviceService.java | 284 +++++---- .../android/server/BluetoothEventLoop.java | 18 +- core/java/android/text/Html.java | 69 ++- core/java/android/text/Layout.java | 105 +++- core/java/android/text/StaticLayout.java | 37 +- core/java/android/view/GestureDetector.java | 2 - core/java/android/view/IWindowManager.aidl | 3 +- core/java/android/view/KeyEvent.java | 72 ++- core/java/android/view/View.java | 5 +- core/java/android/view/ViewDebug.java | 68 ++- core/java/android/view/ViewRoot.java | 24 +- core/java/android/view/ViewTreeObserver.java | 106 ++-- .../android/view/inputmethod/EditorInfo.java | 29 +- core/java/android/webkit/CacheManager.java | 28 +- core/java/android/webkit/HttpAuthHandler.java | 21 +- core/java/android/webkit/LoadListener.java | 41 +- core/java/android/webkit/MimeTypeMap.java | 1 + core/java/android/webkit/Network.java | 18 - core/java/android/webkit/SslErrorHandler.java | 20 +- core/java/android/webkit/WebSettings.java | 15 + core/java/android/webkit/WebView.java | 211 ++++++- core/java/android/widget/AbsListView.java | 8 +- core/java/android/widget/AbsSeekBar.java | 17 +- core/java/android/widget/FrameLayout.java | 47 +- core/java/android/widget/MediaController.java | 2 + core/java/android/widget/PopupWindow.java | 42 +- core/java/android/widget/RatingBar.java | 8 +- core/java/android/widget/RelativeLayout.java | 5 +- core/java/android/widget/TextView.java | 150 +++-- core/java/android/widget/ZoomButton.java | 13 - .../android/widget/ZoomButtonsController.java | 356 ++++------- core/java/android/widget/ZoomControls.java | 5 - .../android/internal/app/AlertController.java | 9 +- .../android/internal/app/IBatteryStats.aidl | 10 +- .../internal/app/RingtonePickerActivity.java | 10 +- .../android/internal/os/BatteryStatsImpl.java | 200 ++++++- .../internal/view/menu/IconMenuItemView.java | 29 +- .../internal/view/menu/IconMenuView.java | 15 +- .../android_location_GpsLocationProvider.cpp | 37 +- core/jni/android_os_Hardware.cpp | 29 - core/jni/android_os_Power.cpp | 7 - core/res/assets/webkit/youtube.html | 2 +- .../res/anim/input_method_extract_enter.xml | 24 + .../res/anim/input_method_extract_exit.xml | 25 + .../drawable-land/statusbar_background.png | Bin 4995 -> 4475 bytes core/res/res/drawable/code_lock_left.9.png | Bin 136 -> 131 bytes ..._btn_square_browser_zoom_page_overview.xml | 20 + ...re_browser_zoom_page_overview_disabled.png | Bin 0 -> 461 bytes ...are_browser_zoom_page_overview_normal.png} | Bin .../res/drawable/status_bar_background.9.png | Bin 220 -> 0 bytes .../res/drawable/status_bar_background.png | Bin 0 -> 3109 bytes .../res/drawable/status_bar_close_on.9.png | Bin 1151 -> 646 bytes ...png => status_bar_header_background.9.png} | Bin 2867 -> 2867 bytes .../status_bar_item_background_normal.9.png | Bin 210 -> 186 bytes .../res/res/drawable/statusbar_background.png | Bin 3519 -> 3160 bytes .../res/res/drawable/title_bar_portrait.9.png | Bin 0 -> 4121 bytes core/res/res/layout/always_use_checkbox.xml | 6 +- core/res/res/layout/input_method.xml | 31 +- .../keyguard_screen_unlock_landscape.xml | 4 +- .../keyguard_screen_unlock_portrait.xml | 8 +- core/res/res/layout/screen_simple.xml | 9 +- core/res/res/layout/status_bar.xml | 2 +- core/res/res/layout/status_bar_expanded.xml | 126 ++-- core/res/res/layout/status_bar_tracking.xml | 8 +- core/res/res/values-cs/strings.xml | 32 +- core/res/res/values-de/strings.xml | 32 +- core/res/res/values-es/strings.xml | 32 +- core/res/res/values-fr/strings.xml | 36 +- core/res/res/values-it/strings.xml | 34 +- core/res/res/values-ja/strings.xml | 80 ++- core/res/res/values-ko/strings.xml | 32 +- core/res/res/values-nb/strings.xml | 32 +- core/res/res/values-nl/strings.xml | 32 +- core/res/res/values-pl/strings.xml | 32 +- core/res/res/values-ru/strings.xml | 32 +- core/res/res/values-zh-rCN/strings.xml | 32 +- core/res/res/values-zh-rTW/strings.xml | 32 +- core/res/res/values/attrs.xml | 51 +- core/res/res/values/public.xml | 3 + core/res/res/values/strings.xml | 13 +- core/res/res/values/styles.xml | 10 +- core/res/res/values/themes.xml | 29 +- docs/html/sdk/OLD_RELEASENOTES.jd | 527 ++++++++++++++++ docs/html/sdk/older_releases.jd | 234 ++++++++ docs/html/sdk/sdk_toc.cs | 1 + include/media/mediarecorder.h | 3 +- include/private/media/AudioTrackShared.h | 3 +- include/utils/ResourceTypes.h | 2 +- libs/audioflinger/AudioFlinger.cpp | 165 +++-- libs/audioflinger/AudioFlinger.h | 3 +- libs/audioflinger/AudioMixer.cpp | 5 +- .../location/GpsLocationProvider.java | 91 ++- media/java/android/media/AudioManager.java | 27 +- media/java/android/media/AudioTrack.java | 16 +- media/java/android/media/JetPlayer.java | 154 +++-- media/java/android/media/MediaPlayer.java | 30 +- media/java/android/media/MediaRecorder.java | 27 + media/jni/android_media_MediaRecorder.cpp | 14 + media/libmedia/AudioTrack.cpp | 4 +- media/libmedia/JetPlayer.cpp | 12 +- media/libmedia/mediarecorder.cpp | 5 +- .../MediaFrameworkTestRunner.java | 10 +- .../functional/MediaMimeTest.java | 139 +++++ packages/SettingsProvider/etc/Android.mk | 14 - packages/SettingsProvider/etc/favorites.xml | 23 - .../com/android/server/BatteryService.java | 20 +- .../com/android/server/HardwareService.java | 77 ++- .../com/android/server/HeadsetObserver.java | 8 +- .../server/InputMethodManagerService.java | 33 +- .../com/android/server/KeyInputQueue.java | 2 +- .../server/LocationManagerService.java | 61 +- .../server/NotificationManagerService.java | 79 ++- .../android/server/PackageManagerService.java | 71 ++- .../android/server/PowerManagerService.java | 57 +- .../java/com/android/server/SystemServer.java | 20 +- .../java/com/android/server/ViewServer.java | 40 +- .../java/com/android/server/WifiService.java | 53 +- .../android/server/WindowManagerService.java | 39 +- .../server/am/ActivityManagerService.java | 38 +- .../server/am/BatteryStatsService.java | 60 +- .../server/status/StatusBarPolicy.java | 15 +- .../server/status/StatusBarService.java | 17 +- .../server/status/TrackingPatternView.java | 72 +++ .../com_android_server_HardwareService.cpp | 100 +++- services/jni/onload.cpp | 4 +- .../internal/telephony/CallerInfo.java | 1 + .../internal/telephony/Connection.java | 16 +- .../internal/telephony/gsm/DriverCall.java | 24 +- .../internal/telephony/gsm/GSMCall.java | 2 +- .../internal/telephony/gsm/GSMConnection.java | 8 + .../android/internal/telephony/gsm/RIL.java | 11 +- .../telephony/gsm/ServiceStateTracker.java | 155 +++-- .../res/values-12key-63x57/configVarying.xml | 22 + .../res/values-12key-dpad/configVarying.xml | 22 + .../res/values-12key/configVarying.xml | 4 - .../res/values-240dpi/configVarying.xml | 22 + .../res/values-320x200/configVarying.xml | 4 - .../configVarying.xml | 22 + .../res/values-32dpi-stylus/configVarying.xml | 22 + .../res/values-480x320/configVarying.xml | 4 - .../res/values-dpad-63x57/configVarying.xml | 22 + .../res/values-finger/configVarying.xml | 4 - .../configVarying.xml | 22 + .../values-keysexposed-dpad/configVarying.xml | 22 + .../res/values-land/configVarying.xml | 22 + .../values-mcc111-mnc222/configVarying.xml | 22 + .../values-mcc111-xx-rYY/configVarying.xml | 22 + .../res/values-mcc111-xx/configVarying.xml | 22 + .../res/values-mcc111/configVarying.xml | 4 - .../values-mnc222-square/configVarying.xml | 22 + .../res/values-mnc222-xx/configVarying.xml | 22 + .../res/values-mnc222/configVarying.xml | 4 - .../res/values-notouch/configVarying.xml | 4 - .../res/values-port/configVarying.xml | 22 + .../res/values-square-32dpi/configVarying.xml | 22 + .../values-square-stylus/configVarying.xml | 22 + .../res/values-square/configVarying.xml | 22 + .../res/values-stylus-12key/configVarying.xml | 22 + .../configVarying.xml | 22 + .../res/values-stylus/configVarying.xml | 4 - .../res/values-xx-32dpi/configVarying.xml | 22 + .../res/values-xx-rYY/configVarying.xml | 4 - .../res/values-xx-square/configVarying.xml | 22 + .../res/values-xx/configVarying.xml | 4 - .../AndroidTests/res/values/configVarying.xml | 5 - .../unit_tests/content/ConfigTest.java | 564 ++++++++++++------ .../settings/BrightnessLimit.java | 2 +- .../statusbartest/NotificationTestList.java | 86 ++- .../layoutlib/bridge/BridgeTypedArray.java | 11 +- 196 files changed, 5945 insertions(+), 2074 deletions(-) create mode 100644 core/res/res/anim/input_method_extract_enter.xml create mode 100644 core/res/res/anim/input_method_extract_exit.xml create mode 100644 core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.xml create mode 100644 core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_disabled.png rename core/res/res/drawable/{ic_btn_square_browser_zoom_page_overview.png => ic_btn_square_browser_zoom_page_overview_normal.png} (100%) delete mode 100644 core/res/res/drawable/status_bar_background.9.png create mode 100644 core/res/res/drawable/status_bar_background.png rename core/res/res/drawable/{status_bar_divider_shadow.9.png => status_bar_header_background.9.png} (93%) create mode 100644 core/res/res/drawable/title_bar_portrait.9.png create mode 100644 docs/html/sdk/OLD_RELEASENOTES.jd create mode 100644 docs/html/sdk/older_releases.jd create mode 100644 media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java delete mode 100644 packages/SettingsProvider/etc/favorites.xml create mode 100644 services/java/com/android/server/status/TrackingPatternView.java create mode 100644 tests/AndroidTests/res/values-12key-63x57/configVarying.xml create mode 100644 tests/AndroidTests/res/values-12key-dpad/configVarying.xml create mode 100644 tests/AndroidTests/res/values-240dpi/configVarying.xml create mode 100644 tests/AndroidTests/res/values-32dpi-keysexposed/configVarying.xml create mode 100644 tests/AndroidTests/res/values-32dpi-stylus/configVarying.xml create mode 100644 tests/AndroidTests/res/values-dpad-63x57/configVarying.xml create mode 100644 tests/AndroidTests/res/values-keysexposed-12key/configVarying.xml create mode 100644 tests/AndroidTests/res/values-keysexposed-dpad/configVarying.xml create mode 100644 tests/AndroidTests/res/values-land/configVarying.xml create mode 100644 tests/AndroidTests/res/values-mcc111-mnc222/configVarying.xml create mode 100644 tests/AndroidTests/res/values-mcc111-xx-rYY/configVarying.xml create mode 100644 tests/AndroidTests/res/values-mcc111-xx/configVarying.xml create mode 100644 tests/AndroidTests/res/values-mnc222-square/configVarying.xml create mode 100644 tests/AndroidTests/res/values-mnc222-xx/configVarying.xml create mode 100644 tests/AndroidTests/res/values-port/configVarying.xml create mode 100644 tests/AndroidTests/res/values-square-32dpi/configVarying.xml create mode 100644 tests/AndroidTests/res/values-square-stylus/configVarying.xml create mode 100644 tests/AndroidTests/res/values-square/configVarying.xml create mode 100644 tests/AndroidTests/res/values-stylus-12key/configVarying.xml create mode 100644 tests/AndroidTests/res/values-stylus-keysexposed/configVarying.xml create mode 100644 tests/AndroidTests/res/values-xx-32dpi/configVarying.xml create mode 100644 tests/AndroidTests/res/values-xx-square/configVarying.xml diff --git a/api/current.xml b/api/current.xml index f45b68f04b8eb..c9ed3c42ddebc 100644 --- a/api/current.xml +++ b/api/current.xml @@ -3771,6 +3771,39 @@ visibility="public" > + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + - - - - - - - - + - + - + - + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index c2d8da519f754..161bb462ddf83 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -528,8 +528,14 @@ public final class Pm { case PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY: s = "INSTALL_FAILED_MISSING_SHARED_LIBRARY"; break; - case PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE: - s = "INSTALL_FAILED_REPLACE_COULDNT_DELETE"; + case PackageManager.INSTALL_FAILED_DEXOPT: + s = "INSTALL_FAILED_DEXOPT"; + break; + case PackageManager.INSTALL_FAILED_OLDER_SDK: + s = "INSTALL_FAILED_OLDER_SDK"; + break; + case PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER: + s = "INSTALL_FAILED_CONFLICTING_PROVIDER"; break; case PackageManager.INSTALL_PARSE_FAILED_NOT_APK: s = "INSTALL_PARSE_FAILED_NOT_APK"; @@ -561,9 +567,6 @@ public final class Pm { case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY: s = "INSTALL_PARSE_FAILED_MANIFEST_EMPTY"; break; - case PackageManager.INSTALL_FAILED_OLDER_SDK: - s = "INSTALL_FAILED_OLDER_SDK"; - break; default: s = Integer.toString(result); break; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f49005ec0e5c9..cb1e903d2bb3e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3250,8 +3250,21 @@ public final class ActivityThread { r.window = null; r.hideForNow = false; r.nextIdle = null; - r.pendingResults = tmp.pendingResults; - r.pendingIntents = tmp.pendingIntents; + // Merge any pending results and pending intents; don't just replace them + if (tmp.pendingResults != null) { + if (r.pendingResults == null) { + r.pendingResults = tmp.pendingResults; + } else { + r.pendingResults.addAll(tmp.pendingResults); + } + } + if (tmp.pendingIntents != null) { + if (r.pendingIntents == null) { + r.pendingIntents = tmp.pendingIntents; + } else { + r.pendingIntents.addAll(tmp.pendingIntents); + } + } r.startsNotResumed = tmp.startsNotResumed; if (savedState != null) { r.state = savedState; diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index 3b5ad862710f5..ecef38f4378e4 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -103,6 +103,9 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; +import java.util.Set; +import java.util.HashSet; import java.util.Map.Entry; import org.xmlpull.v1.XmlPullParserException; @@ -2476,7 +2479,8 @@ class ApplicationContext extends Context { private final FileStatus mFileStatus = new FileStatus(); private long mTimestamp; - private List mListeners; + private static final Object mContent = new Object(); + private WeakHashMap mListeners; SharedPreferencesImpl( File file, int mode, Map initialContents) { @@ -2487,7 +2491,7 @@ class ApplicationContext extends Context { if (FileUtils.getFileStatus(file.getPath(), mFileStatus)) { mTimestamp = mFileStatus.mtime; } - mListeners = new ArrayList(); + mListeners = new WeakHashMap(); } public boolean hasFileChanged() { @@ -2509,9 +2513,7 @@ class ApplicationContext extends Context { public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { synchronized(this) { - if (!mListeners.contains(listener)) { - mListeners.add(listener); - } + mListeners.put(listener, mContent); } } @@ -2620,13 +2622,14 @@ class ApplicationContext extends Context { boolean hasListeners; List keysModified = null; - List listeners = null; + Set listeners = null; synchronized (SharedPreferencesImpl.this) { hasListeners = mListeners.size() > 0; if (hasListeners) { keysModified = new ArrayList(); - listeners = new ArrayList(mListeners); + listeners = + new HashSet(mListeners.keySet()); } synchronized (this) { @@ -2635,9 +2638,7 @@ class ApplicationContext extends Context { mClear = false; } - Iterator> it = mModified.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry e = it.next(); + for (Entry e : mModified.entrySet()) { String k = e.getKey(); Object v = e.getValue(); if (v == this) { @@ -2660,10 +2661,10 @@ class ApplicationContext extends Context { if (hasListeners) { for (int i = keysModified.size() - 1; i >= 0; i--) { final String key = keysModified.get(i); - // Call in the order they were registered - final int listenersSize = listeners.size(); - for (int j = 0; j < listenersSize; j++) { - listeners.get(j).onSharedPreferenceChanged(SharedPreferencesImpl.this, key); + for (OnSharedPreferenceChangeListener listener : listeners) { + if (listener != null) { + listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key); + } } } } diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java index d6fcbb1a6aa7e..8d249da960bdb 100644 --- a/core/java/android/app/LauncherActivity.java +++ b/core/java/android/app/LauncherActivity.java @@ -65,6 +65,7 @@ public abstract class LauncherActivity extends ListActivity { public Drawable icon; public String packageName; public String className; + public Bundle extras; ListItem(PackageManager pm, ResolveInfo resolveInfo, IconResizer resizer) { label = resolveInfo.loadLabel(pm); @@ -115,6 +116,9 @@ public abstract class LauncherActivity extends ListActivity { Intent intent = new Intent(mIntent); ListItem item = mActivitiesList.get(position); intent.setClassName(item.packageName, item.className); + if (item.extras != null) { + intent.putExtras(item.extras); + } return intent; } diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index a6a436f4fd097..d2fb6052e9ade 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -278,11 +278,11 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac } /** - * Stop the service, if the most recent time it was started was + * Stop the service if the most recent time it was started was * startId. This is the same as calling {@link * android.content.Context#stopService} for this particular service but allows you to * safely avoid stopping if there is a start request from a client that you - * haven't yet see in {@link #onStart}. + * haven't yet seen in {@link #onStart}. * * @param startId The most recent start identifier received in {@link * #onStart}. diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 3b10ed282d1c7..eca04b3113308 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -108,6 +108,23 @@ public class AppWidgetManager { */ public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds"; + /** + * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of + * {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are + * installed. (This is how the launcher shows the search widget). + */ + public static final String EXTRA_CUSTOM_INFO = "customInfo"; + + /** + * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of + * {@link android.os.Bundle} objects to mix in to the list of AppWidgets that are + * installed. It will be added to the extras object on the {@link android.content.Intent} + * that is returned from the picker activity. + * + * {@more} + */ + public static final String EXTRA_CUSTOM_EXTRAS = "customExtras"; + /** * A sentiel value that the AppWidget manager will never return as a appWidgetId. */ diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 1ba1c1e86f7b9..abf08cbfc7658 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -31,6 +31,12 @@ import java.io.UnsupportedEncodingException; * @hide */ public class BluetoothDevice { + + public static final int BLUETOOTH_STATE_OFF = 0; + public static final int BLUETOOTH_STATE_TURNING_ON = 1; + public static final int BLUETOOTH_STATE_ON = 2; + public static final int BLUETOOTH_STATE_TURNING_OFF = 3; + /** Inquiry scan and page scan are both off. * Device is neither discoverable nor connectable */ public static final int SCAN_MODE_NONE = 0; @@ -83,7 +89,7 @@ public class BluetoothDevice { } /** - * Get the current status of Bluetooth hardware. + * Is Bluetooth currently turned on. * * @return true if Bluetooth enabled, false otherwise. */ @@ -94,38 +100,31 @@ public class BluetoothDevice { return false; } + /** + * Get the current state of Bluetooth. + * + * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR. + */ + public int getBluetoothState() { + try { + return mService.getBluetoothState(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return BluetoothError.ERROR; + } + /** * Enable the Bluetooth device. * Turn on the underlying hardware. - * This is an asynchronous call, BluetoothIntent.ENABLED_ACTION will be - * sent if and when the device is successfully enabled. + * This is an asynchronous call, + * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if + * and when the device is sucessfully enabled. * @return false if we cannot enable the Bluetooth device. True does not * imply the device was enabled, it only implies that so far there were no * problems. */ public boolean enable() { - return enable(null); - } - - /** - * Enable the Bluetooth device. - * Turns on the underlying hardware. - * This is an asynchronous call. onEnableResult() of your callback will be - * called when the call is complete, with either RESULT_SUCCESS or - * RESULT_FAILURE. - * - * Your callback will be called from a binder thread, not the main thread. - * - * In addition to the callback, BluetoothIntent.ENABLED_ACTION will be - * broadcast if the device is successfully enabled. - * - * @param callback Your callback, null is ok. - * @return true if your callback was successfully registered, or false if - * there was an error, implying your callback will never be called. - */ - public boolean enable(IBluetoothDeviceCallback callback) { try { - return mService.enable(callback); + return mService.enable(); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -138,7 +137,7 @@ public class BluetoothDevice { */ public boolean disable() { try { - return mService.disable(); + return mService.disable(true); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -551,7 +550,6 @@ public class BluetoothDevice { } return pinBytes; } - private static final int ADDRESS_LENGTH = 17; /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */ diff --git a/core/java/android/bluetooth/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java index 9273d0defaeb0..344601b0b89a8 100644 --- a/core/java/android/bluetooth/BluetoothIntent.java +++ b/core/java/android/bluetooth/BluetoothIntent.java @@ -41,6 +41,10 @@ public interface BluetoothIntent { "android.bluetooth.intent.RSSI"; public static final String CLASS = "android.bluetooth.intent.CLASS"; + public static final String BLUETOOTH_STATE = + "android.bluetooth.intent.BLUETOOTH_STATE"; + public static final String BLUETOOTH_PREVIOUS_STATE = + "android.bluetooth.intent.BLUETOOTH_PREVIOUS_STATE"; public static final String HEADSET_STATE = "android.bluetooth.intent.HEADSET_STATE"; public static final String HEADSET_PREVIOUS_STATE = @@ -54,12 +58,12 @@ public interface BluetoothIntent { public static final String REASON = "android.bluetooth.intent.REASON"; + /** Broadcast when the local Bluetooth device state changes, for example + * when Bluetooth is enabled. Will contain int extra's BLUETOOTH_STATE and + * BLUETOOTH_PREVIOUS_STATE. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ENABLED_ACTION = - "android.bluetooth.intent.action.ENABLED"; - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String DISABLED_ACTION = - "android.bluetooth.intent.action.DISABLED"; + public static final String BLUETOOTH_STATE_CHANGED_ACTION = + "android.bluetooth.intent.action.BLUETOOTH_STATE_CHANGED"; @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String NAME_CHANGED_ACTION = diff --git a/core/java/android/bluetooth/IBluetoothDevice.aidl b/core/java/android/bluetooth/IBluetoothDevice.aidl index 4351d2ebc3863..6cd792e26a52a 100644 --- a/core/java/android/bluetooth/IBluetoothDevice.aidl +++ b/core/java/android/bluetooth/IBluetoothDevice.aidl @@ -26,8 +26,9 @@ import android.bluetooth.IBluetoothDeviceCallback; interface IBluetoothDevice { boolean isEnabled(); - boolean enable(in IBluetoothDeviceCallback callback); // async - boolean disable(); + int getBluetoothState(); + boolean enable(); + boolean disable(boolean persistSetting); String getAddress(); String getName(); diff --git a/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl b/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl index d25bd560d0347..d05709330b761 100644 --- a/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl +++ b/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl @@ -22,6 +22,4 @@ package android.bluetooth; oneway interface IBluetoothDeviceCallback { void onGetRemoteServiceChannelResult(in String address, int channel); - - void onEnableResult(int result); } diff --git a/core/java/android/bluetooth/ScoSocket.java b/core/java/android/bluetooth/ScoSocket.java index a43a08be10567..1bf786ffd3adc 100644 --- a/core/java/android/bluetooth/ScoSocket.java +++ b/core/java/android/bluetooth/ScoSocket.java @@ -76,7 +76,7 @@ public class ScoSocket { try { if (VDBG) log(this + " SCO OBJECT DTOR"); destroyNative(); - releaseWakeLock(); + releaseWakeLockNow(); } finally { super.finalize(); } @@ -98,7 +98,7 @@ public class ScoSocket { return true; } else { mState = STATE_CLOSED; - releaseWakeLock(); + releaseWakeLockNow(); return false; } } @@ -148,7 +148,7 @@ public class ScoSocket { mState = STATE_CLOSED; } mHandler.obtainMessage(mConnectedCode, mState, -1, this).sendToTarget(); - releaseWakeLock(); + releaseWakeLockNow(); } private synchronized void onAccepted(int result) { @@ -183,7 +183,19 @@ public class ScoSocket { private void releaseWakeLock() { if (mWakeLock.isHeld()) { - if (VDBG) log("mWakeLock.release() " + this); + // Keep apps processor awake for a further 2 seconds. + // This is a hack to resolve issue http://b/1616263 - in which + // we are left in a 80 mA power state when remotely terminating a + // call while connected to BT headset "HTC BH S100 " with A2DP and + // HFP profiles. + if (VDBG) log("mWakeLock.release() in 2 sec" + this); + mWakeLock.acquire(2000); + } + } + + private void releaseWakeLockNow() { + if (mWakeLock.isHeld()) { + if (VDBG) log("mWakeLock.release() now" + this); mWakeLock.release(); } } diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index 08f6191ac71e7..a41627aa3ab4d 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -68,7 +68,7 @@ import android.util.Log; * these broadcasts, the Intent broadcast mechanism here is completely separate * from Intents that are used to start Activities with * {@link Context#startActivity Context.startActivity()}. - * There is no way for an BroadcastReceiver + * There is no way for a BroadcastReceiver * to see or capture Intents used with startActivity(); likewise, when * you broadcast an Intent, you will never find or start an Activity. * These two operations are semantically very different: starting an @@ -103,7 +103,7 @@ import android.util.Log; * its process before the asynchronous operation completes. * *

In particular, you may not show a dialog or bind to a service from - * within an BroadcastReceiver. For the former, you should instead use the + * within a BroadcastReceiver. For the former, you should instead use the * {@link android.app.NotificationManager} API. For the latter, you can * use {@link android.content.Context#startService Context.startService()} to * send a command to the service. @@ -141,7 +141,7 @@ import android.util.Log; * *

Process Lifecycle

* - *

A process that is currently executing an BroadcastReceiver (that is, + *

A process that is currently executing a BroadcastReceiver (that is, * currently running the code in its {@link #onReceive} method) is * considered to be a foreground process and will be kept running by the * system except under cases of extreme memory pressure. @@ -156,7 +156,7 @@ import android.util.Log; * more important processes. * *

This means that for longer-running operations you will often use - * a {@link android.app.Service} in conjunction with an BroadcastReceiver to keep + * an {@link android.app.Service} in conjunction with a BroadcastReceiver to keep * the containing process active for the entire time of your operation. */ public abstract class BroadcastReceiver { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 90ff78a59485c..306c02eca3d82 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1035,7 +1035,7 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS"; - + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent broadcast actions (see action variable). @@ -1052,7 +1052,7 @@ public class Intent implements Parcelable { public static final String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON"; /** - * Broadcast Action: Sent when the user is present after device wakes up (e.g when the + * Broadcast Action: Sent when the user is present after device wakes up (e.g when the * keyguard is gone). */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @@ -1210,7 +1210,7 @@ public class Intent implements Parcelable { /** * Broadcast Action: The charging state, or charge level of the battery has * changed. - * + * *

* You can not receive this through components declared * in manifests, only by exlicitly registering for it with @@ -1380,7 +1380,7 @@ public class Intent implements Parcelable { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED"; - + /** * Broadcast Action: An input method has been changed. * {@hide pending API Council approval} @@ -1450,12 +1450,12 @@ public class Intent implements Parcelable { * *

The Intent will have the following extra value: *

    - *
  • {@link android.content.Intent#EXTRA_PHONE_NUMBER} - + *
  • {@link android.content.Intent#EXTRA_PHONE_NUMBER} - * the phone number originally intended to be dialed.
  • *
*

Once the broadcast is finished, the resultData is used as the actual * number to call. If null, no call will be placed.

- *

It is perfectly acceptable for multiple receivers to process the + *

It is perfectly acceptable for multiple receivers to process the * outgoing call in turn: for example, a parental control application * might verify that the user is authorized to place the call at that * time, then a number-rewriting application might add an area code if @@ -1463,7 +1463,7 @@ public class Intent implements Parcelable { *

For consistency, any receiver whose purpose is to prohibit phone * calls should have a priority of 0, to ensure it will see the final * phone number to be dialed. - * Any receiver whose purpose is to rewrite phone numbers to be called + * Any receiver whose purpose is to rewrite phone numbers to be called * should have a positive priority. * Negative priorities are reserved for the system for this broadcast; * using them may cause problems.

@@ -1472,7 +1472,7 @@ public class Intent implements Parcelable { *

Emergency calls cannot be intercepted using this mechanism, and * other calls cannot be modified to call emergency numbers using this * mechanism. - *

You must hold the + *

You must hold the * {@link android.Manifest.permission#PROCESS_OUTGOING_CALLS} * permission to receive this Intent.

*/ @@ -1709,7 +1709,7 @@ public class Intent implements Parcelable { * implying that this is an update). */ public static final String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED"; - + /** * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED} * intents to indicate that this is a replacement of the package, so this @@ -1717,7 +1717,7 @@ public class Intent implements Parcelable { * different version of the same package. */ public static final String EXTRA_REPLACING = "android.intent.extra.REPLACING"; - + /** * Used as an int extra field in {@link android.app.AlarmManager} intents * to tell the application being invoked how many pending alarms are being @@ -1728,15 +1728,6 @@ public class Intent implements Parcelable { */ public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT"; - /** - * Used as an int extra field in {@link android.content.Intent#ACTION_VOICE_COMMAND} - * intents to request which audio route the voice command should prefer. - * The value should be a route from {@link android.media.AudioManager}, for - * example ROUTE_BLUETOOTH_SCO. Providing this value is optional. - * {@hide pending API Council approval} - */ - public static final String EXTRA_AUDIO_ROUTE = "android.intent.extra.AUDIO_ROUTE"; - // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Intent flags (see mFlags variable). @@ -1781,7 +1772,7 @@ public class Intent implements Parcelable { * next task activity) defines an atomic group of activities that the * user can move to. Tasks can be moved to the foreground and background; * all of the activities inside of a particular task always remain in - * the same order. See + * the same order. See * Application Fundamentals: * Activities and Tasks for more details on tasks. * @@ -1812,7 +1803,7 @@ public class Intent implements Parcelable { *

Because the default system does not include graphical task management, * you should not use this flag unless you provide some way for a user to * return back to the tasks you have launched. - * + * *

This flag is ignored if * {@link #FLAG_ACTIVITY_NEW_TASK} is not set. * @@ -1901,7 +1892,7 @@ public class Intent implements Parcelable { * the user re-launching it from home), this activity and all on top of * it will be finished so that the user does not return to them, but * instead returns to whatever activity preceeded it. - * + * *

This is useful for cases where you have a logical break in your * application. For example, an e-mail application may have a command * to view an attachment, which launches an image view activity to @@ -1919,31 +1910,31 @@ public class Intent implements Parcelable { * If set, this flag will prevent the normal {@link android.app.Activity#onUserLeaveHint} * callback from occurring on the current frontmost activity before it is * paused as the newly-started activity is brought to the front. - * + * *

Typically, an activity can rely on that callback to indicate that an * explicit user action has caused their activity to be moved out of the * foreground. The callback marks an appropriate point in the activity's * lifecycle for it to dismiss any notifications that it intends to display * "until the user has seen them," such as a blinking LED. - * + * *

If an activity is ever started via any non-user-driven events such as * phone-call receipt or an alarm handler, this flag should be passed to {@link * Context#startActivity Context.startActivity}, ensuring that the pausing - * activity does not think the user has acknowledged its notification. + * activity does not think the user has acknowledged its notification. */ public static final int FLAG_ACTIVITY_NO_USER_ACTION = 0x00040000; /** * If set in an Intent passed to {@link Context#startActivity Context.startActivity()}, * this flag will cause the launched activity to be brought to the front of its * task's history stack if it is already running. - * + * *

For example, consider a task consisting of four activities: A, B, C, D. * If D calls startActivity() with an Intent that resolves to the component * of activity B, then B will be brought to the front of the history stack, * with this resulting order: A, C, D, B. - * + * * This flag will be ignored if {@link #FLAG_ACTIVITY_CLEAR_TOP} is also - * specified. + * specified. */ public static final int FLAG_ACTIVITY_REORDER_TO_FRONT = 0X00020000; /** @@ -1957,11 +1948,11 @@ public class Intent implements Parcelable { * will be launched. Sticky intent state will be recorded properly even * if no receivers wind up being called. If {@link #FLAG_RECEIVER_REGISTERED_ONLY} * is specified in the broadcast intent, this flag is unnecessary. - * + * *

This flag is only for use by system sevices as a convenience to * avoid having to implement a more complex mechanism around detection * of boot completion. - * + * * @hide */ public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x20000000; @@ -2121,7 +2112,7 @@ public class Intent implements Parcelable { // old format Intent URI if (!uri.startsWith("#Intent;", i)) return getIntentOld(uri); - + // new format Intent intent = new Intent(ACTION_VIEW); @@ -2130,7 +2121,7 @@ public class Intent implements Parcelable { intent.mData = Uri.parse(uri.substring(0, i)); } i += "#Intent;".length(); - + // loop over contents of Intent, all name=value; while (!uri.startsWith("end", i)) { int eq = uri.indexOf('=', i); @@ -2161,7 +2152,7 @@ public class Intent implements Parcelable { else if (uri.startsWith("component=", i)) { intent.mComponent = ComponentName.unflattenFromString(value); } - + // extra else { String key = Uri.decode(uri.substring(i + 2, eq)); @@ -2181,18 +2172,18 @@ public class Intent implements Parcelable { else if (uri.startsWith("s.", i)) b.putShort(key, Short.parseShort(value)); else throw new URISyntaxException(uri, "unknown EXTRA type", i); } - + // move to the next item i = semi + 1; } return intent; - + } catch (IndexOutOfBoundsException e) { throw new URISyntaxException(uri, "illegal Intent URI format", i); } } - + public static Intent getIntentOld(String uri) throws URISyntaxException { Intent intent; @@ -2257,7 +2248,7 @@ public class Intent implements Parcelable { if (uri.regionMatches(i, "extras(", 0, 7)) { i += 7; - + final int closeParen = uri.indexOf(')', i); if (closeParen == -1) throw new URISyntaxException(uri, "EXTRA missing trailing ')'", i); @@ -2272,7 +2263,7 @@ public class Intent implements Parcelable { i++; String key = uri.substring(i, j); i = j + 1; - + // get type-value j = uri.indexOf('!', i); if (j == -1 || j >= closeParen) j = closeParen; @@ -2282,7 +2273,7 @@ public class Intent implements Parcelable { // create Bundle if it doesn't already exist if (intent.mExtras == null) intent.mExtras = new Bundle(); - + // add item to bundle try { switch (type) { @@ -2319,7 +2310,7 @@ public class Intent implements Parcelable { } catch (NumberFormatException e) { throw new URISyntaxException(uri, "EXTRA value can't be parsed", i); } - + char ch = uri.charAt(i); if (ch == ')') break; if (ch != '!') throw new URISyntaxException(uri, "EXTRA missing '!'", i); @@ -2522,7 +2513,7 @@ public class Intent implements Parcelable { public boolean hasFileDescriptors() { return mExtras != null && mExtras.hasFileDescriptors(); } - + /** * Retrieve extended data from the intent. * @@ -3889,7 +3880,7 @@ public class Intent implements Parcelable { /** * Completely replace the extras in the Intent with the extras in the * given Intent. - * + * * @param src The exact extras contained in this Intent are copied * into the target intent, replacing any that were previously there. */ @@ -3897,11 +3888,11 @@ public class Intent implements Parcelable { mExtras = src.mExtras != null ? new Bundle(src.mExtras) : null; return this; } - + /** * Completely replace the extras in the Intent with the given Bundle of * extras. - * + * * @param extras The new set of extras in the Intent, or null to erase * all extras. */ @@ -3909,7 +3900,7 @@ public class Intent implements Parcelable { mExtras = extras != null ? new Bundle(extras) : null; return this; } - + /** * Remove extended data from the intent. * @@ -4397,12 +4388,12 @@ public class Intent implements Parcelable { } } } - + uri.append("end"); return uri.toString(); } - + public int describeContents() { return (mExtras != null) ? mExtras.describeContents() : 0; } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 7287d9cd58e93..3e9473472dcb3 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -340,6 +340,14 @@ public abstract class PackageManager { */ public static final int INSTALL_FAILED_OLDER_SDK = -12; + /** + * Installation return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if + * the new package failed because it contains a content provider with the + * same authority as a provider already installed in the system. + */ + public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13; + /** * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} diff --git a/core/java/android/emoji/EmojiFactory.java b/core/java/android/emoji/EmojiFactory.java index 389bd07d6b735..e0b12ae31d9a6 100644 --- a/core/java/android/emoji/EmojiFactory.java +++ b/core/java/android/emoji/EmojiFactory.java @@ -253,6 +253,22 @@ public final class EmojiFactory { * is returned. */ public static native EmojiFactory newAvailableInstance(); + + /** + * Returns the lowest code point corresponding to an Android + * emoji character. + */ + public int getMinimumAndroidPua() { + return nativeGetMinimumAndroidPua(mNativeEmojiFactory); + } + + /** + * Returns the highest code point corresponding to an Android + * emoji character. + */ + public int getMaximumAndroidPua() { + return nativeGetMaximumAndroidPua(mNativeEmojiFactory); + } // native methods diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 32270c46d039a..6ee92ce6b019a 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -22,8 +22,8 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.app.Dialog; import android.content.Context; import android.content.res.Configuration; +import android.content.res.TypedArray; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.IBinder; import android.os.ResultReceiver; @@ -44,6 +44,7 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; +import android.view.animation.AnimationUtils; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; @@ -54,6 +55,8 @@ import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.FrameLayout; +import android.widget.LinearLayout; + import java.io.FileDescriptor; import java.io.PrintWriter; @@ -204,6 +207,10 @@ import java.io.PrintWriter; * You can use these to reset and initialize your input state for the current * target. For example, you will often want to clear any input state, and * update a soft keyboard to be appropriate for the new inputType.

+ * + * @attr ref android.R.styleable#InputMethodService_imeFullscreenBackground + * @attr ref android.R.styleable#InputMethodService_imeExtractEnterAnimation + * @attr ref android.R.styleable#InputMethodService_imeExtractExitAnimation */ public class InputMethodService extends AbstractInputMethodService { static final String TAG = "InputMethodService"; @@ -211,13 +218,19 @@ public class InputMethodService extends AbstractInputMethodService { InputMethodManager mImm; + int mTheme = android.R.style.Theme_InputMethod; + LayoutInflater mInflater; + TypedArray mThemeAttrs; View mRootView; SoftInputWindow mWindow; boolean mInitialized; boolean mWindowCreated; boolean mWindowAdded; boolean mWindowVisible; + boolean mWindowWasVisible; + boolean mInShowWindow; + ViewGroup mFullscreenArea; FrameLayout mExtractFrame; FrameLayout mCandidatesFrame; FrameLayout mInputFrame; @@ -243,6 +256,7 @@ public class InputMethodService extends AbstractInputMethodService { boolean mFullscreenApplied; boolean mIsFullscreen; View mExtractView; + boolean mExtractViewHidden; ExtractEditText mExtractEditText; ViewGroup mExtractAccessories; Button mExtractAction; @@ -260,8 +274,8 @@ public class InputMethodService extends AbstractInputMethodService { final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = new ViewTreeObserver.OnComputeInternalInsetsListener() { public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { - if (isFullscreenMode()) { - // In fullscreen mode, we just say the window isn't covering + if (isExtractViewShown()) { + // In true fullscreen mode, we just say the window isn't covering // any content so we don't impact whatever is behind. View decor = getWindow().getWindow().getDecorView(); info.contentInsets.top = info.visibleInsets.top @@ -519,12 +533,28 @@ public class InputMethodService extends AbstractInputMethodService { public int touchableInsets; } + /** + * You can call this to customize the theme used by your IME's window. + * This theme should typically be one that derives from + * {@link android.R.style#Theme_InputMethod}, which is the default theme + * you will get. This must be set before {@link #onCreate}, so you + * will typically call it in your constructor with the resource ID + * of your custom theme. + */ + public void setTheme(int theme) { + if (mWindow != null) { + throw new IllegalStateException("Must be called before onCreate()"); + } + mTheme = theme; + } + @Override public void onCreate() { + super.setTheme(mTheme); super.onCreate(); mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); mInflater = (LayoutInflater)getSystemService( Context.LAYOUT_INFLATER_SERVICE); - mWindow = new SoftInputWindow(this); + mWindow = new SoftInputWindow(this, mTheme); initViews(); mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT); } @@ -551,6 +581,7 @@ public class InputMethodService extends AbstractInputMethodService { mShowInputRequested = false; mShowInputForced = false; + mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService); mRootView = mInflater.inflate( com.android.internal.R.layout.input_method, null); mWindow.setContentView(mRootView); @@ -560,6 +591,8 @@ public class InputMethodService extends AbstractInputMethodService { mWindow.getWindow().setWindowAnimations( com.android.internal.R.style.Animation_InputMethodFancy); } + mFullscreenArea = (ViewGroup)mRootView.findViewById(com.android.internal.R.id.fullscreenArea); + mExtractViewHidden = false; mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea); mExtractView = null; mExtractEditText = null; @@ -731,14 +764,20 @@ public class InputMethodService extends AbstractInputMethodService { if (ic != null) ic.reportFullscreenMode(isFullscreen); mFullscreenApplied = true; initialize(); - Drawable bg = onCreateBackgroundDrawable(); - if (bg == null) { - // We need to give the window a real drawable, so that it - // correctly sets its mode. - bg = getResources().getDrawable(android.R.color.transparent); + LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) + mFullscreenArea.getLayoutParams(); + if (isFullscreen) { + mFullscreenArea.setBackgroundDrawable(mThemeAttrs.getDrawable( + com.android.internal.R.styleable.InputMethodService_imeFullscreenBackground)); + lp.height = 0; + lp.weight = 1; + } else { + mFullscreenArea.setBackgroundDrawable(null); + lp.height = LinearLayout.LayoutParams.WRAP_CONTENT; + lp.weight = 0; } - mWindow.getWindow().setBackgroundDrawable(bg); - mExtractFrame.setVisibility(isFullscreen ? View.VISIBLE : View.GONE); + ((ViewGroup)mFullscreenArea.getParent()).updateViewLayout( + mFullscreenArea, lp); if (isFullscreen) { if (mExtractView == null) { View v = onCreateExtractTextView(); @@ -748,6 +787,7 @@ public class InputMethodService extends AbstractInputMethodService { } startExtractingText(false); } + updateExtractFrameVisibility(); } if (changed) { @@ -804,13 +844,67 @@ public class InputMethodService extends AbstractInputMethodService { return config.orientation == Configuration.ORIENTATION_LANDSCAPE; } + /** + * Controls the visibility of the extracted text area. This only applies + * when the input method is in fullscreen mode, and thus showing extracted + * text. When false, the extracted text will not be shown, allowing some + * of the application to be seen behind. This is normally set for you + * by {@link #onUpdateExtractingVisibility}. This controls the visibility + * of both the extracted text and candidate view; the latter since it is + * not useful if there is no text to see. + */ + public void setExtractViewShown(boolean shown) { + if (mExtractViewHidden == shown) { + mExtractViewHidden = !shown; + updateExtractFrameVisibility(); + } + } + + /** + * Return whether the fullscreen extract view is shown. This will only + * return true if {@link #isFullscreenMode()} returns true, and in that + * case its value depends on the last call to + * {@link #setExtractViewShown(boolean)}. This effectively lets you + * determine if the application window is entirely covered (when this + * returns true) or if some part of it may be shown (if this returns + * false, though if {@link #isFullscreenMode()} returns true in that case + * then it is probably only a sliver of the application). + */ + public boolean isExtractViewShown() { + return mIsFullscreen && !mExtractViewHidden; + } + + void updateExtractFrameVisibility() { + int vis; + if (isFullscreenMode()) { + vis = mExtractViewHidden ? View.INVISIBLE : View.VISIBLE; + mExtractFrame.setVisibility(View.VISIBLE); + } else { + vis = View.VISIBLE; + mExtractFrame.setVisibility(View.GONE); + } + updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE); + if (mWindowWasVisible && mFullscreenArea.getVisibility() != vis) { + int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE + ? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation + : com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation, + 0); + if (animRes != 0) { + mFullscreenArea.startAnimation(AnimationUtils.loadAnimation( + this, animRes)); + } + } + mFullscreenArea.setVisibility(vis); + } + /** * Compute the interesting insets into your UI. The default implementation * uses the top of the candidates frame for the visible insets, and the * top of the input frame for the content insets. The default touchable * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}. * - *

Note that this method is not called when in fullscreen mode, since + *

Note that this method is not called when + * {@link #isExtractViewShown} returns true, since * in that case the application is left as-is behind the input method and * not impacted by anything in its UI. * @@ -821,9 +915,16 @@ public class InputMethodService extends AbstractInputMethodService { if (mInputFrame.getVisibility() == View.VISIBLE) { mInputFrame.getLocationInWindow(loc); } else { - loc[1] = 0; + View decor = getWindow().getWindow().getDecorView(); + loc[1] = decor.getHeight(); + } + if (isFullscreenMode()) { + // In fullscreen mode, we never resize the underlying window. + View decor = getWindow().getWindow().getDecorView(); + outInsets.contentTopInsets = decor.getHeight(); + } else { + outInsets.contentTopInsets = loc[1]; } - outInsets.contentTopInsets = loc[1]; if (mCandidatesFrame.getVisibility() == View.VISIBLE) { mCandidatesFrame.getLocationInWindow(loc); } @@ -889,11 +990,7 @@ public class InputMethodService extends AbstractInputMethodService { * it is hidden. */ public void setCandidatesViewShown(boolean shown) { - int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility(); - if (mCandidatesVisibility != vis) { - mCandidatesFrame.setVisibility(vis); - mCandidatesVisibility = vis; - } + updateCandidatesVisibility(shown); if (!mShowInputRequested && mWindowVisible != shown) { // If we are being asked to show the candidates view while the app // has not asked for the input view to be shown, then we need @@ -906,17 +1003,26 @@ public class InputMethodService extends AbstractInputMethodService { } } + void updateCandidatesVisibility(boolean shown) { + int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility(); + if (mCandidatesVisibility != vis) { + mCandidatesFrame.setVisibility(vis); + mCandidatesVisibility = vis; + } + } + /** * Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE} * or {@link View#GONE View.GONE}) of the candidates view when it is not - * shown. The default implementation returns GONE when in fullscreen mode, + * shown. The default implementation returns GONE when + * {@link #isExtractViewShown} returns true, * otherwise VISIBLE. Be careful if you change this to return GONE in * other situations -- if showing or hiding the candidates view causes * your window to resize, this can cause temporary drawing artifacts as * the resize takes place. */ public int getCandidatesHiddenVisibility() { - return isFullscreenMode() ? View.GONE : View.INVISIBLE; + return isExtractViewShown() ? View.GONE : View.INVISIBLE; } public void showStatusIcon(int iconResId) { @@ -991,20 +1097,6 @@ public class InputMethodService extends AbstractInputMethodService { mInputView = view; } - /** - * Called by the framework to create a Drawable for the background of - * the input method window. May return null for no background. The default - * implementation returns a non-null standard background only when in - * fullscreen mode. This is called each time the fullscreen mode changes. - */ - public Drawable onCreateBackgroundDrawable() { - if (isFullscreenMode()) { - return getResources().getDrawable( - com.android.internal.R.drawable.input_method_fullscreen_background); - } - return null; - } - /** * Called by the framework to create the layout for showing extacted text. * Only called when in fullscreen mode. The returned view hierarchy must @@ -1174,6 +1266,23 @@ public class InputMethodService extends AbstractInputMethodService { + " mWindowCreated=" + mWindowCreated + " mWindowVisible=" + mWindowVisible + " mInputStarted=" + mInputStarted); + + if (mInShowWindow) { + Log.w(TAG, "Re-entrance in to showWindow"); + return; + } + + try { + mWindowWasVisible = mWindowVisible; + mInShowWindow = true; + showWindowInner(showInput); + } finally { + mWindowWasVisible = true; + mInShowWindow = false; + } + } + + void showWindowInner(boolean showInput) { boolean doShowInput = false; boolean wasVisible = mWindowVisible; mWindowVisible = true; @@ -1241,6 +1350,7 @@ public class InputMethodService extends AbstractInputMethodService { mWindow.hide(); mWindowVisible = false; onWindowHidden(); + mWindowWasVisible = false; } } @@ -1559,7 +1669,7 @@ public class InputMethodService extends AbstractInputMethodService { boolean doMovementKey(int keyCode, KeyEvent event, int count) { final ExtractEditText eet = mExtractEditText; - if (isFullscreenMode() && isInputViewShown() && eet != null) { + if (isExtractViewShown() && isInputViewShown() && eet != null) { // If we are in fullscreen mode, the cursor will move around // the extract edit text, but should NOT cause focus to move // to other fields. @@ -1583,10 +1693,10 @@ public class InputMethodService extends AbstractInputMethodService { if (movement.onKeyOther(eet, (Spannable)eet.getText(), event)) { reportExtractedMovement(keyCode, count); } else { - KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN); + KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN); if (movement.onKeyDown(eet, (Spannable)eet.getText(), keyCode, down)) { - KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP); + KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP); movement.onKeyUp(eet, (Spannable)eet.getText(), keyCode, up); while (--count > 0) { @@ -1800,18 +1910,52 @@ public class InputMethodService extends AbstractInputMethodService { } /** - * Called when it is time to update the actions available from a full-screen - * IME. You do not need to deal with this if you are using the standard - * full screen extract UI. If replacing it, you will need to re-implement - * this to put the action in your own UI and handle it. + * Called when the fullscreen-mode extracting editor info has changed, + * to determine whether the extracting (extract text and candidates) portion + * of the UI should be shown. The standard implementation hides or shows + * the extract area depending on whether it makes sense for the + * current editor. In particular, a {@link InputType#TYPE_NULL} + * input type or {@link EditorInfo#IME_FLAG_NO_EXTRACT_UI} flag will + * turn off the extract area since there is no text to be shown. */ - public void onUpdateExtractingAccessories(EditorInfo ei) { + public void onUpdateExtractingVisibility(EditorInfo ei) { + if (ei.inputType == InputType.TYPE_NULL || + (ei.imeOptions&EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0) { + // No reason to show extract UI! + setExtractViewShown(false); + return; + } + + setExtractViewShown(true); + } + + /** + * Called when the fullscreen-mode extracting editor info has changed, + * to update the state of its UI such as the action buttons shown. + * You do not need to deal with this if you are using the standard + * full screen extract UI. If replacing it, you will need to re-implement + * this to put the appropriate action button in your own UI and handle it, + * and perform any other changes. + * + *

The standard implementation turns on or off its accessory area + * depending on whether there is an action button, and hides or shows + * the entire extract area depending on whether it makes sense for the + * current editor. In particular, a {@link InputType#TYPE_NULL} or + * {@link InputType#TYPE_TEXT_VARIATION_FILTER} input type will turn off the + * extract area since there is no text to be shown. + */ + public void onUpdateExtractingViews(EditorInfo ei) { + if (!isExtractViewShown()) { + return; + } + if (mExtractAccessories == null) { return; } final boolean hasAction = ei.actionLabel != null || ( (ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE && - (ei.imeOptions&EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0); + (ei.imeOptions&EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION) == 0 && + ei.inputType != InputType.TYPE_NULL); if (hasAction) { mExtractAccessories.setVisibility(View.VISIBLE); if (ei.actionLabel != null) { @@ -1855,7 +1999,8 @@ public class InputMethodService extends AbstractInputMethodService { try { eet.startInternalChanges(); - onUpdateExtractingAccessories(ei); + onUpdateExtractingVisibility(ei); + onUpdateExtractingViews(ei); int inputType = ei.inputType; if ((inputType&EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) { @@ -1890,8 +2035,10 @@ public class InputMethodService extends AbstractInputMethodService { final Printer p = new PrintWriterPrinter(fout); p.println("Input method service state for " + this + ":"); p.println(" mWindowCreated=" + mWindowCreated - + " mWindowAdded=" + mWindowAdded - + " mWindowVisible=" + mWindowVisible); + + " mWindowAdded=" + mWindowAdded); + p.println(" mWindowVisible=" + mWindowVisible + + " mWindowWasVisible=" + mWindowWasVisible + + " mInShowWindow=" + mInShowWindow); p.println(" Configuration=" + getResources().getConfiguration()); p.println(" mToken=" + mToken); p.println(" mInputBinding=" + mInputBinding); @@ -1914,7 +2061,8 @@ public class InputMethodService extends AbstractInputMethodService { + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags)); p.println(" mCandidatesVisibility=" + mCandidatesVisibility + " mFullscreenApplied=" + mFullscreenApplied - + " mIsFullscreen=" + mIsFullscreen); + + " mIsFullscreen=" + mIsFullscreen + + " mExtractViewHidden=" + mExtractViewHidden); if (mExtractedText != null) { p.println(" mExtractedText:"); diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java index c37845f02b632..d91ace6b778f6 100644 --- a/core/java/android/inputmethodservice/SoftInputWindow.java +++ b/core/java/android/inputmethodservice/SoftInputWindow.java @@ -31,18 +31,6 @@ import android.view.WindowManager; */ class SoftInputWindow extends Dialog { - /** - * Create a DockWindow that uses the default style. - * - * @param context The Context the DockWindow is to run it. In particular, it - * uses the window manager and theme in this context to present its - * UI. - */ - public SoftInputWindow(Context context) { - super(context, com.android.internal.R.style.Theme_InputMethod); - initDockWindow(); - } - public void setToken(IBinder token) { WindowManager.LayoutParams lp = getWindow().getAttributes(); lp.token = token; diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 7590bfef45355..76c74df27838a 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -4,6 +4,8 @@ import java.io.PrintWriter; import java.util.Formatter; import java.util.Map; +import com.android.internal.os.BatteryStatsImpl.Timer; + import android.util.Log; import android.util.Printer; import android.util.SparseArray; @@ -39,6 +41,20 @@ public abstract class BatteryStats implements Parcelable { * {@hide} */ public static final int SENSOR = 3; + + /** + * A constant indicating a full wifi lock timer + * + * {@hide} + */ + public static final int FULL_WIFI_LOCK = 4; + + /** + * A constant indicating a scan wifi lock timer + * + * {@hide} + */ + public static final int SCAN_WIFI_LOCK = 5; /** * Include all of the data in the stats, including previously saved data. @@ -74,6 +90,7 @@ public abstract class BatteryStats implements Parcelable { private static final String WAKELOCK_DATA = "wakelock"; private static final String NETWORK_DATA = "network"; private static final String BATTERY_DATA = "battery"; + private static final String WIFI_LOCK_DATA = "wifilock"; private static final String MISC_DATA = "misc"; private final StringBuilder mFormatBuilder = new StringBuilder(8); @@ -162,6 +179,13 @@ public abstract class BatteryStats implements Parcelable { * {@hide} */ public abstract long getTcpBytesSent(int which); + + public abstract void noteFullWifiLockAcquiredLocked(); + public abstract void noteFullWifiLockReleasedLocked(); + public abstract void noteScanWifiLockAcquiredLocked(); + public abstract void noteScanWifiLockReleasedLocked(); + public abstract long getFullWifiLockTime(long batteryRealtime, int which); + public abstract long getScanWifiLockTime(long batteryRealtime, int which); public static abstract class Sensor { // Magic sensor number for the GPS. @@ -269,6 +293,22 @@ public abstract class BatteryStats implements Parcelable { */ public abstract long getPhoneOnTime(long batteryRealtime, int which); + /** + * Returns the time in milliseconds that wifi has been on while the device was + * running on battery. + * + * {@hide} + */ + public abstract long getWifiOnTime(long batteryRealtime, int which); + + /** + * Returns the time in milliseconds that bluetooth has been on while the device was + * running on battery. + * + * {@hide} + */ + public abstract long getBluetoothOnTime(long batteryRealtime, int which); + /** * Return whether we are currently running on battery. */ @@ -292,6 +332,17 @@ public abstract class BatteryStats implements Parcelable { * @param curTime the amount of elapsed realtime in microseconds. */ public abstract long getBatteryRealtime(long curTime); + + /** + * Returns the battery percentage level at the last time the device was unplugged from power, + * or the last time it was booted while unplugged. + */ + public abstract int getUnpluggedStartLevel(); + + /** + * Returns the battery percentage level at the last time the device was plugged into power. + */ + public abstract int getPluggedStartLevel(); /** * Returns the total, last, or current battery uptime in microseconds. @@ -483,6 +534,8 @@ public abstract class BatteryStats implements Parcelable { final long totalUptime = computeUptime(rawUptime, which); final long screenOnTime = getScreenOnTime(batteryRealtime, which); final long phoneOnTime = getPhoneOnTime(batteryRealtime, which); + final long wifiOnTime = getWifiOnTime(batteryRealtime, which); + final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which); StringBuilder sb = new StringBuilder(128); @@ -496,7 +549,12 @@ public abstract class BatteryStats implements Parcelable { // Dump misc stats dumpLine(pw, 0 /* uid */, category, MISC_DATA, - screenOnTime / 1000, phoneOnTime / 1000); + screenOnTime / 1000, phoneOnTime / 1000, wifiOnTime / 1000, bluetoothOnTime / 1000); + + if (which == STATS_UNPLUGGED) { + dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, getUnpluggedStartLevel(), + getPluggedStartLevel()); + } SparseArray uidStats = getUidStats(); final int NU = uidStats.size(); @@ -506,7 +564,15 @@ public abstract class BatteryStats implements Parcelable { // Dump Network stats per uid, if any long rx = u.getTcpBytesReceived(which); long tx = u.getTcpBytesSent(which); + long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which); + long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which); + if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx); + + if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) { + dumpLine(pw, uid, category, WIFI_LOCK_DATA, + fullWifiLockOnTime, scanWifiLockOnTime); + } Map wakelocks = u.getWakelockStats(); if (wakelocks.size() > 0) { @@ -624,13 +690,35 @@ public abstract class BatteryStats implements Parcelable { + formatTimeMs(totalRealtime / 1000) + "realtime"); - long screenOnTime = getScreenOnTime(batteryRealtime, which); - long phoneOnTime = getPhoneOnTime(batteryRealtime, which); + final long screenOnTime = getScreenOnTime(batteryRealtime, which); + final long phoneOnTime = getPhoneOnTime(batteryRealtime, which); + final long wifiOnTime = getWifiOnTime(batteryRealtime, which); + final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which); pw.println(prefix + " Time with screen on: " + formatTimeMs(screenOnTime / 1000) + "(" + formatRatioLocked(screenOnTime, whichBatteryRealtime) + "), time with phone on: " + formatTimeMs(phoneOnTime / 1000) - + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime) + ")"); + + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime) + + "), time with wifi on: " + formatTimeMs(wifiOnTime / 1000) + + "(" + formatRatioLocked(wifiOnTime, whichBatteryRealtime) + + "), time with bluetooth on: " + formatTimeMs(bluetoothOnTime / 1000) + + "(" + formatRatioLocked(bluetoothOnTime, whichBatteryRealtime)+ ")"); + + pw.println(" "); + + if (which == STATS_UNPLUGGED) { + if (getIsOnBattery()) { + pw.println(prefix + " Device is currently unplugged"); + pw.println(prefix + " Discharge cycle start level: " + + getUnpluggedStartLevel()); + } else { + pw.println(prefix + " Device is currently plugged into power"); + pw.println(prefix + " Last discharge cycle start level: " + + getUnpluggedStartLevel()); + pw.println(prefix + " Last discharge cycle end level: " + + getPluggedStartLevel()); + } + } pw.println(" "); @@ -644,10 +732,23 @@ public abstract class BatteryStats implements Parcelable { long tcpReceived = u.getTcpBytesReceived(which); long tcpSent = u.getTcpBytesSent(which); + long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which); + long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which); + if (tcpReceived != 0 || tcpSent != 0) { pw.println(prefix + " Network: " + tcpReceived + " bytes received, " + tcpSent + " bytes sent"); } + if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) { + pw.println(prefix + " Full Wifi Lock Time: " + + formatTime(fullWifiLockOnTime / 1000) + + "(" + formatRatioLocked(fullWifiLockOnTime, + whichBatteryRealtime)+ ")"); + pw.println(prefix + " Scan Wifi Lock Time: " + + formatTime(scanWifiLockOnTime / 1000) + + "(" + formatRatioLocked(scanWifiLockOnTime, + whichBatteryRealtime)+ ")"); + } Map wakelocks = u.getWakelockStats(); if (wakelocks.size() > 0) { diff --git a/core/java/android/os/Hardware.java b/core/java/android/os/Hardware.java index 3b6c9d7b2defe..efc5617451fc1 100644 --- a/core/java/android/os/Hardware.java +++ b/core/java/android/os/Hardware.java @@ -21,22 +21,29 @@ package android.os; */ public class Hardware { - /** - * Control the LED. - */ - public static native int setLedState(int colorARGB, int onMS, int offMS); - - /** - * Control the Flashlight - */ + + + /* ******************************************************************************** + * + * + * + * + * + * + * + * + * Don't add anything else to this class. Add it to HardwareService instead. + * + * + * + * + * + * + * + * ********************************************************************************/ + + public static native boolean getFlashlightEnabled(); public static native void setFlashlightEnabled(boolean on); public static native void enableCameraFlash(int milliseconds); - - /** - * Control the backlights - */ - public static native void setScreenBacklight(int brightness); - public static native void setKeyboardBacklight(boolean on); - public static native void setButtonBacklight(boolean on); } diff --git a/core/java/android/os/IHardwareService.aidl b/core/java/android/os/IHardwareService.aidl index 4f6029f59fb2f..fb121bb5e2ee1 100755 --- a/core/java/android/os/IHardwareService.aidl +++ b/core/java/android/os/IHardwareService.aidl @@ -29,12 +29,10 @@ interface IHardwareService void setFlashlightEnabled(boolean on); void enableCameraFlash(int milliseconds); - // backlight support - void setScreenBacklight(int brightness); - void setKeyboardBacklight(boolean on); - void setButtonBacklight(boolean on); - - // LED support - void setLedState(int colorARGB, int onMS, int offMS); + // sets the brightness of the backlights (screen, keyboard, button) 0-255 + void setBacklights(int brightness); + + // for the phone + void setAttentionLight(boolean on); } diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java index b53e22704d1f5..47497e547ff1f 100644 --- a/core/java/android/os/Power.java +++ b/core/java/android/os/Power.java @@ -44,26 +44,6 @@ public class Power public static native void acquireWakeLock(int lock, String id); public static native void releaseWakeLock(String id); - /** - * Flag to turn on and off the keyboard light. - */ - public static final int KEYBOARD_LIGHT = 0x00000001; - - /** - * Flag to turn on and off the screen backlight. - */ - public static final int SCREEN_LIGHT = 0x00000002; - - /** - * Flag to turn on and off the button backlight. - */ - public static final int BUTTON_LIGHT = 0x00000004; - - /** - * Flags to turn on and off all the backlights. - */ - public static final int ALL_LIGHTS = (KEYBOARD_LIGHT|SCREEN_LIGHT|BUTTON_LIGHT); - /** * Brightness value for fully off */ @@ -90,14 +70,6 @@ public class Power */ public static final int LOW_BATTERY_THRESHOLD = 10; - /** - * Set the brightness for one or more lights - * - * @param mask flags indicating which lights to change brightness - * @param brightness new brightness value (0 = off, 255 = fully bright) - */ - public static native int setLightBrightness(int mask, int brightness); - /** * Turn the screen on or off * diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index 04e7ef05c3a2d..63f6dffba87e5 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -211,7 +211,7 @@ public class RemoteCallbackList { for (Callback cb : mCallbacks.values()) { active[i++] = cb.mCallback; } - return N; + return i; } } diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java index d75a25fe8a35d..4a709f6c7517a 100644 --- a/core/java/android/provider/Calendar.java +++ b/core/java/android/provider/Calendar.java @@ -1054,6 +1054,9 @@ public final class Calendar { if (cursor == null) { return; } + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "missed alarms found: " + cursor.getCount()); + } try { while (cursor.moveToNext()) { @@ -1068,6 +1071,8 @@ public final class Calendar { intent.putExtra(android.provider.Calendar.EVENT_END_TIME, end); PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + Log.w(TAG, "rescheduling missed alarm, id: " + id + " begin: " + begin + + " end: " + end + " alarmTime: " + alarmTime); manager.set(AlarmManager.RTC_WAKEUP, alarmTime, sender); } } finally { diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 10fe3f5c5487f..abd6934a86b39 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -22,6 +22,8 @@ import android.content.Context; import android.net.Uri; import android.provider.Contacts.People; import com.android.internal.telephony.CallerInfo; +import com.android.internal.telephony.Connection; + import android.text.TextUtils; import android.util.Log; @@ -137,7 +139,8 @@ public class CallLog { * if the contact is unknown. * @param context the context used to get the ContentResolver * @param number the phone number to be added to the calls db - * @param isPrivateNumber true if the call was marked as private by the network + * @param presentation the number presenting rules set by the network for + * "allowed", "payphone", "restricted" or "unknown" * @param callType enumerated values for "incoming", "outgoing", or "missed" * @param start time stamp for the call in milliseconds * @param duration call duration in seconds @@ -145,12 +148,14 @@ public class CallLog { * {@hide} */ public static Uri addCall(CallerInfo ci, Context context, String number, - boolean isPrivateNumber, int callType, long start, int duration) { + int presentation, int callType, long start, int duration) { final ContentResolver resolver = context.getContentResolver(); if (TextUtils.isEmpty(number)) { - if (isPrivateNumber) { + if (presentation == Connection.PRESENTATION_RESTRICTED) { number = CallerInfo.PRIVATE_NUMBER; + } else if (presentation == Connection.PRESENTATION_PAYPHONE) { + number = CallerInfo.PAYPHONE_NUMBER; } else { number = CallerInfo.UNKNOWN_NUMBER; } diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java index 2aa77eab026d3..be31c0a55d815 100644 --- a/core/java/android/provider/Contacts.java +++ b/core/java/android/provider/Contacts.java @@ -1459,13 +1459,24 @@ public class Contacts { "com.android.contacts.action.SHOW_OR_CREATE_CONTACT"; /** - * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new contact if no matching - * contact found. Otherwise, default behavior is to prompt user with dialog before creating. - * - *

Type: BOOLEAN

+ * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new + * contact if no matching contact found. Otherwise, default behavior is + * to prompt user with dialog before creating. + *

+ * Type: BOOLEAN */ public static final String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE"; + + /** + * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact + * description to be shown when prompting user about creating a new + * contact. + *

+ * Type: STRING + */ + public static final String EXTRA_CREATE_DESCRIPTION = + "com.android.contacts.action.CREATE_DESCRIPTION"; /** * Intents related to the Contacts app UI. diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index 3aa407858100c..3c507074af833 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -63,6 +63,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private final IntentFilter mIntentFilter; private HashMap mAudioDevices; private final AudioManager mAudioManager; + private final BluetoothDevice mBluetooth; private class SinkState { public String address; @@ -75,9 +76,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - BluetoothDevice device = - (BluetoothDevice)mContext.getSystemService(Context.BLUETOOTH_SERVICE); - if (device == null) { + mBluetooth = (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE); + if (mBluetooth == null) { throw new RuntimeException("Platform does not support Bluetooth"); } @@ -85,13 +85,12 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { throw new RuntimeException("Could not init BluetoothA2dpService"); } - mIntentFilter = new IntentFilter(BluetoothIntent.ENABLED_ACTION); - mIntentFilter.addAction(BluetoothIntent.DISABLED_ACTION); + mIntentFilter = new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION); mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION); mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION); mContext.registerReceiver(mReceiver, mIntentFilter); - if (device.isEnabled()) { + if (mBluetooth.isEnabled()) { onBluetoothEnable(); } } @@ -110,10 +109,17 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); String address = intent.getStringExtra(BluetoothIntent.ADDRESS); - if (action.equals(BluetoothIntent.ENABLED_ACTION)) { - onBluetoothEnable(); - } else if (action.equals(BluetoothIntent.DISABLED_ACTION)) { - onBluetoothDisable(); + if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) { + int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE, + BluetoothError.ERROR); + switch (state) { + case BluetoothDevice.BLUETOOTH_STATE_ON: + onBluetoothEnable(); + break; + case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF: + onBluetoothDisable(); + break; + } } else if (action.equals(BluetoothIntent.BOND_STATE_CHANGED_ACTION)) { int bondState = intent.getIntExtra(BluetoothIntent.BOND_STATE, BluetoothError.ERROR); @@ -145,9 +151,10 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { switch (msg.what) { case MESSAGE_CONNECT_TO: String address = (String)msg.obj; - // check device is still preferred, and nothing is currently - // connected - if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF && + // check bluetooth is still on, device is still preferred, and + // nothing is currently connected + if (mBluetooth.isEnabled() && + getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF && lookupSinksMatchingStates(new int[] { BluetoothA2dp.STATE_CONNECTING, BluetoothA2dp.STATE_CONNECTED, diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java index 9e9ba6237613a..b7e3846ab9eb2 100644 --- a/core/java/android/server/BluetoothDeviceService.java +++ b/core/java/android/server/BluetoothDeviceService.java @@ -37,8 +37,10 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Binder; import android.os.Handler; +import android.os.IBinder; import android.os.Message; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemService; import android.provider.Settings; import android.util.Log; @@ -51,6 +53,8 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import com.android.internal.app.IBatteryStats; + public class BluetoothDeviceService extends IBluetoothDevice.Stub { private static final String TAG = "BluetoothDeviceService"; private static final boolean DBG = true; @@ -60,14 +64,18 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private IntentFilter mIntentFilter; private boolean mIsAirplaneSensitive; private final BondState mBondState = new BondState(); // local cache of bondings - private volatile boolean mIsEnabled; // local cache of isEnabledNative() + private int mBluetoothState; private boolean mIsDiscovering; + private final IBatteryStats mBatteryStats; private final Context mContext; private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; + private static final int MESSAGE_REGISTER_SDP_RECORDS = 1; + private static final int MESSAGE_FINISH_DISABLE = 2; + static { classInitNative(); } @@ -75,6 +83,12 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { public BluetoothDeviceService(Context context) { mContext = context; + + // Need to do this in place of: + // mBatteryStats = BatteryStatsService.getService(); + // Since we can not import BatteryStatsService from here. This class really needs to be + // moved to java/services/com/android/server/ + mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); } /** Must be called after construction, and before any other method. @@ -87,7 +101,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { disableNative(); } - mIsEnabled = false; + setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF); mIsDiscovering = false; mEventLoop = new BluetoothEventLoop(mContext, this); registerForAirplaneMode(); @@ -109,10 +123,16 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { public boolean isEnabled() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - return mIsEnabled; + return mBluetoothState == BluetoothDevice.BLUETOOTH_STATE_ON; } private native int isEnabledNative(); + public int getBluetoothState() { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); + return mBluetoothState; + } + + /** * Bring down bluetooth and disable BT in settings. Returns true on success. */ @@ -124,17 +144,36 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * Bring down bluetooth. Returns true on success. * * @param saveSetting If true, disable BT in settings - * */ public synchronized boolean disable(boolean saveSetting) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); + switch (mBluetoothState) { + case BluetoothDevice.BLUETOOTH_STATE_OFF: + return true; + case BluetoothDevice.BLUETOOTH_STATE_ON: + break; + default: + return false; + } if (mEnableThread != null && mEnableThread.isAlive()) { return false; } - if (!mIsEnabled) { - return true; + setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF); + + // Allow 3 seconds for profiles to gracefully disconnect + // TODO: Introduce a callback mechanism so that each profile can notify + // BluetoothDeviceService when it is done shutting down + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000); + return true; + } + + + private synchronized void finishDisable(boolean saveSetting) { + if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) { + return; } mEventLoop.stop(); disableNative(); @@ -163,38 +202,37 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothDevice.SCAN_MODE_NONE); mContext.sendBroadcast(intent, BLUETOOTH_PERM); - mIsEnabled = false; + mIsDiscovering = false; + if (saveSetting) { persistBluetoothOnSetting(false); } - mIsDiscovering = false; - intent = new Intent(BluetoothIntent.DISABLED_ACTION); - mContext.sendBroadcast(intent, BLUETOOTH_PERM); - return true; + + setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF); + + // Log bluetooth off to battery stats. + long ident = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteBluetoothOff(); + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } } - /** - * Bring up bluetooth, asynchronously, and enable BT in settings. - * This turns on/off the underlying hardware. - * - * @return True on success (so far), guaranteeing the callback with be - * notified when complete. - */ - public boolean enable(IBluetoothDeviceCallback callback) { - return enable(callback, true); + /** Bring up BT and persist BT on in settings */ + public boolean enable() { + return enable(true); } /** * Enable this Bluetooth device, asynchronously. * This turns on/off the underlying hardware. * - * @param saveSetting If true, enable BT in settings - * - * @return True on success (so far), guaranteeing the callback with be - * notified when complete. + * @param saveSetting If true, persist the new state of BT in settings + * @return True on success (so far) */ - public synchronized boolean enable(IBluetoothDeviceCallback callback, - boolean saveSetting) { + public synchronized boolean enable(boolean saveSetting) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); @@ -202,28 +240,49 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { if (mIsAirplaneSensitive && isAirplaneModeOn()) { return false; } - if (mIsEnabled) { + if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_OFF) { return false; } if (mEnableThread != null && mEnableThread.isAlive()) { return false; } - mEnableThread = new EnableThread(callback, saveSetting); + setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_ON); + mEnableThread = new EnableThread(saveSetting); mEnableThread.start(); return true; } - private static final int REGISTER_SDP_RECORDS = 1; + private synchronized void setBluetoothState(int state) { + if (state == mBluetoothState) { + return; + } + + if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state); + + Intent intent = new Intent(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION); + intent.putExtra(BluetoothIntent.BLUETOOTH_PREVIOUS_STATE, mBluetoothState); + intent.putExtra(BluetoothIntent.BLUETOOTH_STATE, state); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + + mBluetoothState = state; + + mContext.sendBroadcast(intent, BLUETOOTH_PERM); + } + private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { - case REGISTER_SDP_RECORDS: + case MESSAGE_REGISTER_SDP_RECORDS: //TODO: Don't assume HSP/HFP is running, don't use sdptool, if (isEnabled()) { SystemService.start("hsag"); SystemService.start("hfag"); } + break; + case MESSAGE_FINISH_DISABLE: + finishDisable(msg.arg1 != 0); + break; } } }; @@ -231,10 +290,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private EnableThread mEnableThread; private class EnableThread extends Thread { - private final IBluetoothDeviceCallback mEnableCallback; private final boolean mSaveSetting; - public EnableThread(IBluetoothDeviceCallback callback, boolean saveSetting) { - mEnableCallback = callback; + public EnableThread(boolean saveSetting) { mSaveSetting = saveSetting; } public void run() { @@ -244,7 +301,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { boolean running = false; while ((retryCount-- > 0) && !running) { mEventLoop.start(); - // it may take a momement for the other thread to do its + // it may take a momement for the other thread to do its // thing. Check periodically for a while. int pollCount = 5; while ((pollCount-- > 0) && !running) { @@ -264,36 +321,37 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { } } - if (mEnableCallback != null) { - try { - mEnableCallback.onEnableResult(res ? - BluetoothDevice.RESULT_SUCCESS : - BluetoothDevice.RESULT_FAILURE); - } catch (RemoteException e) {} - } if (res) { - mIsEnabled = true; if (mSaveSetting) { persistBluetoothOnSetting(true); } mIsDiscovering = false; mBondState.loadBondState(); - mHandler.sendMessageDelayed(mHandler.obtainMessage(REGISTER_SDP_RECORDS), 3000); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS), + 3000); + // Log bluetooth on to battery stats. + long ident = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteBluetoothOn(); + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + mEnableThread = null; + + setBluetoothState(res ? + BluetoothDevice.BLUETOOTH_STATE_ON : + BluetoothDevice.BLUETOOTH_STATE_OFF); + + if (res) { // Update mode mEventLoop.onModeChanged(getModeNative()); } - Intent intent = null; - if (res) { - intent = new Intent(BluetoothIntent.ENABLED_ACTION); - } else { - intent = new Intent(BluetoothIntent.DISABLED_ACTION); - } - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcast(intent, BLUETOOTH_PERM); - mEnableThread = null; } } @@ -320,18 +378,24 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private final HashMap mState = new HashMap(); private final HashMap mPinAttempt = new HashMap(); private final ArrayList mAutoPairingFailures = new ArrayList(); - // List of all the vendor_id prefix of Bluetooth addresses for which - // auto pairing is not attempted + // List of all the vendor_id prefix of Bluetooth addresses for + // which auto pairing is not attempted. + // The following companies are included in the list below: + // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi), + // Parrot, Zhongshan General K-mate Electronics, Great Well + // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi, + // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura), private final ArrayList mAutoPairingBlacklisted = new ArrayList(Arrays.asList( - "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", //ALPS - "00:21:4F", "00:23:06", "00:24:33", "00:A0:79", // ALPS - "00:0E:6D", "00:13:E0", "00:21:E8", "00:60:57",// Murata for Prius 2007 - "00:0E:9F" // TEMIC SDS for Porsche + "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F", + "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8", + "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04", + "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59", + "00:0A:30" )); public synchronized void loadBondState() { - if (!mIsEnabled) { + if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_ON) { return; } String[] bonds = listBondingsNative(); @@ -1051,7 +1115,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { // If bluetooth is currently expected to be on, then enable or disable bluetooth if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) { if (enabled) { - enable(null, false); + enable(false); } else { disable(false); } @@ -1079,52 +1143,63 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mIsEnabled) { - pw.println("\nBluetooth ENABLED: " + getAddress() + " (" + getName() + ")"); - pw.println("\nisDiscovering() = " + isDiscovering()); + pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n"); - BluetoothHeadset headset = new BluetoothHeadset(mContext, null); - - String[] addresses = listRemoteDevices(); - - pw.println("\n--Known devices--"); - for (String address : addresses) { - pw.printf("%s %10s (%d) %s\n", address, - toBondStateString(mBondState.getBondState(address)), - mBondState.getAttempt(address), - getRemoteName(address)); - } - - addresses = listAclConnections(); - pw.println("\n--ACL connected devices--"); - for (String address : addresses) { - pw.println(address); - } - - // Rather not do this from here, but no-where else and I need this - // dump - pw.println("\n--Headset Service--"); - switch (headset.getState()) { - case BluetoothHeadset.STATE_DISCONNECTED: - pw.println("getState() = STATE_DISCONNECTED"); - break; - case BluetoothHeadset.STATE_CONNECTING: - pw.println("getState() = STATE_CONNECTING"); - break; - case BluetoothHeadset.STATE_CONNECTED: - pw.println("getState() = STATE_CONNECTED"); - break; - case BluetoothHeadset.STATE_ERROR: - pw.println("getState() = STATE_ERROR"); - break; - } - pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress()); - headset.close(); - - } else { - pw.println("\nBluetooth DISABLED"); + switch(mBluetoothState) { + case BluetoothDevice.BLUETOOTH_STATE_OFF: + pw.println("\nBluetooth OFF\n"); + return; + case BluetoothDevice.BLUETOOTH_STATE_TURNING_ON: + pw.println("\nBluetooth TURNING ON\n"); + return; + case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF: + pw.println("\nBluetooth TURNING OFF\n"); + return; + case BluetoothDevice.BLUETOOTH_STATE_ON: + pw.println("\nBluetooth ON\n"); } - pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive); + + pw.println("\nLocal address = " + getAddress()); + pw.println("\nLocal name = " + getName()); + pw.println("\nisDiscovering() = " + isDiscovering()); + + BluetoothHeadset headset = new BluetoothHeadset(mContext, null); + + String[] addresses = listRemoteDevices(); + + pw.println("\n--Known devices--"); + for (String address : addresses) { + pw.printf("%s %10s (%d) %s\n", address, + toBondStateString(mBondState.getBondState(address)), + mBondState.getAttempt(address), + getRemoteName(address)); + } + + addresses = listAclConnections(); + pw.println("\n--ACL connected devices--"); + for (String address : addresses) { + pw.println(address); + } + + // Rather not do this from here, but no-where else and I need this + // dump + pw.println("\n--Headset Service--"); + switch (headset.getState()) { + case BluetoothHeadset.STATE_DISCONNECTED: + pw.println("getState() = STATE_DISCONNECTED"); + break; + case BluetoothHeadset.STATE_CONNECTING: + pw.println("getState() = STATE_CONNECTING"); + break; + case BluetoothHeadset.STATE_CONNECTED: + pw.println("getState() = STATE_CONNECTED"); + break; + case BluetoothHeadset.STATE_ERROR: + pw.println("getState() = STATE_ERROR"); + break; + } + pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress()); + headset.close(); } /* package */ static int bluezStringToScanMode(String mode) { @@ -1159,3 +1234,4 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { Log.d(TAG, msg); } } + diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 8e77eed9c067c..6be8eb96ba21d 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -46,10 +46,10 @@ class BluetoothEventLoop { private Thread mThread; private boolean mStarted; private boolean mInterrupted; - private HashMap mPasskeyAgentRequestData; - private HashMap mGetRemoteServiceChannelCallbacks; - private BluetoothDeviceService mBluetoothService; - private Context mContext; + private final HashMap mPasskeyAgentRequestData; + private final HashMap mGetRemoteServiceChannelCallbacks; + private final BluetoothDeviceService mBluetoothService; + private final Context mContext; private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1; private static final int EVENT_RESTART_BLUETOOTH = 2; @@ -77,7 +77,7 @@ class BluetoothEventLoop { break; case EVENT_RESTART_BLUETOOTH: mBluetoothService.disable(); - mBluetoothService.enable(null); + mBluetoothService.enable(); break; } } @@ -309,6 +309,12 @@ class BluetoothEventLoop { address = address.toUpperCase(); mPasskeyAgentRequestData.put(address, new Integer(nativeData)); + if (mBluetoothService.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) { + // shutdown path + mBluetoothService.cancelPin(address); + return; + } + if (mBluetoothService.getBondState().getBondState(address) == BluetoothDevice.BOND_BONDING) { // we initiated the bonding @@ -347,7 +353,7 @@ class BluetoothEventLoop { private boolean onAuthAgentAuthorize(String address, String service, String uuid) { boolean authorized = false; - if (service.endsWith("service_audio")) { + if (mBluetoothService.isEnabled() && service.endsWith("service_audio")) { BluetoothA2dp a2dp = new BluetoothA2dp(mContext); authorized = a2dp.getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF; if (authorized) { diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index 849571485dc7a..6f0be3a64f8df 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -28,6 +28,8 @@ import org.xml.sax.XMLReader; import android.content.res.Resources; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.AlignmentSpan; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; @@ -41,6 +43,7 @@ import android.text.style.SuperscriptSpan; import android.text.style.TypefaceSpan; import android.text.style.URLSpan; import android.text.style.UnderlineSpan; +import android.util.Log; import com.android.internal.util.XmlUtils; import java.io.IOException; @@ -137,11 +140,52 @@ public class Html { */ public static String toHtml(Spanned text) { StringBuilder out = new StringBuilder(); + withinHtml(out, text); + return out.toString(); + } + + private static void withinHtml(StringBuilder out, Spanned text) { int len = text.length(); int next; for (int i = 0; i < text.length(); i = next) { - next = text.nextSpanTransition(i, len, QuoteSpan.class); + next = text.nextSpanTransition(i, len, ParagraphStyle.class); + ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class); + if (style.length > 0) { + out.append("

0) { + out.append(">"); + } + + withinDiv(out, text, i, next); + + if (style.length > 0) { + out.append("
"); + } + } + } + + private static void withinDiv(StringBuilder out, Spanned text, + int start, int end) { + int next; + for (int i = start; i < end; i = next) { + next = text.nextSpanTransition(i, end, QuoteSpan.class); QuoteSpan[] quotes = text.getSpans(i, next, QuoteSpan.class); for (QuoteSpan quote: quotes) { @@ -154,8 +198,6 @@ public class Html { out.append("\n"); } } - - return out.toString(); } private static void withinBlockquote(StringBuilder out, Spanned text, @@ -234,11 +276,32 @@ public class Html { // Don't output the dummy character underlying the image. i = next; } + if (style[j] instanceof AbsoluteSizeSpan) { + out.append(""); + } + if (style[j] instanceof ForegroundColorSpan) { + out.append(""); + } } withinStyle(out, text, i, next); for (int j = style.length - 1; j >= 0; j--) { + if (style[j] instanceof ForegroundColorSpan) { + out.append(""); + } + if (style[j] instanceof AbsoluteSizeSpan) { + out.append(""); + } if (style[j] instanceof URLSpan) { out.append(""); } diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 95acf9d236171..23e740d305141 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -16,6 +16,8 @@ package android.text; +import android.emoji.EmojiFactory; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; @@ -36,6 +38,20 @@ import android.view.KeyEvent; * For text that will not change, use a {@link StaticLayout}. */ public abstract class Layout { + /* package */ static final EmojiFactory EMOJI_FACTORY = + EmojiFactory.newAvailableInstance(); + /* package */ static final int MIN_EMOJI, MAX_EMOJI; + + static { + if (EMOJI_FACTORY != null) { + MIN_EMOJI = EMOJI_FACTORY.getMinimumAndroidPua(); + MAX_EMOJI = EMOJI_FACTORY.getMaximumAndroidPua(); + } else { + MIN_EMOJI = -1; + MAX_EMOJI = -1; + } + }; + /** * Return how wide a layout would be necessary to display the * specified text with one line per paragraph. @@ -445,7 +461,9 @@ public abstract class Layout { public abstract int getParagraphDirection(int line); /** - * Returns whether the specified line contains one or more tabs. + * Returns whether the specified line contains one or more + * characters that need to be handled specially, like tabs + * or emoji. */ public abstract boolean getLineContainsTab(int line); @@ -1352,6 +1370,26 @@ public abstract class Layout { h = dir * nextTab(text, start, end, h * dir, parspans); segstart = j + 1; + } else if (hasTabs && buf[j] >= 0xD800 && buf[j] <= 0xDFFF && j + 1 < there) { + int emoji = Character.codePointAt(buf, j); + + if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) { + Bitmap bm = EMOJI_FACTORY. + getBitmapFromAndroidPua(emoji); + + if (bm != null) { + h += Styled.drawText(canvas, text, + start + segstart, start + j, + dir, (i & 1) != 0, x + h, + top, y, bottom, paint, workPaint, + start + j != end); + + canvas.drawBitmap(bm, x + h, y - bm.getHeight(), paint); + h += bm.getWidth(); + j++; + segstart = j + 1; + } + } } } @@ -1394,7 +1432,22 @@ public abstract class Layout { int segstart = here; for (int j = hasTabs ? here : there; j <= there; j++) { - if (j == there || buf[j] == '\t') { + int codept = 0; + Bitmap bm = null; + + if (hasTabs && j < there) { + codept = buf[j]; + } + + if (codept >= 0xD800 && codept <= 0xDFFF && j + 1 < there) { + codept = Character.codePointAt(buf, j); + + if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) { + bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept); + } + } + + if (j == there || codept == '\t' || bm != null) { float segw; if (offset < start + j || @@ -1449,6 +1502,16 @@ public abstract class Layout { h = dir * nextTab(text, start, end, h * dir, tabs); } + if (bm != null) { + if (dir == DIR_RIGHT_TO_LEFT) { + h -= bm.getWidth(); + } else { + h += bm.getWidth(); + } + + j++; + } + segstart = j + 1; } } @@ -1488,7 +1551,22 @@ public abstract class Layout { } for (int i = hasTabs ? 0 : len; i <= len; i++) { - if (i == len || buf[i] == '\t') { + int codept = 0; + Bitmap bm = null; + + if (hasTabs && i < len) { + codept = buf[i]; + } + + if (codept >= 0xD800 && codept <= 0xDFFF && i < len) { + codept = Character.codePointAt(buf, i); + + if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) { + bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept); + } + } + + if (i == len || codept == '\t' || bm != null) { workPaint.baselineShift = 0; h += Styled.measureText(paint, workPaint, text, @@ -1505,8 +1583,14 @@ public abstract class Layout { } } - if (i != len) - h = nextTab(text, start, end, h, tabs); + if (i != len) { + if (bm == null) { + h = nextTab(text, start, end, h, tabs); + } else { + h += bm.getWidth(); + i++; + } + } if (fm != null) { if (fm.ascent < ab) { @@ -1522,6 +1606,17 @@ public abstract class Layout { if (fm.bottom > bot) { bot = fm.bottom; } + + if (bm != null) { + int ht = -bm.getHeight(); + + if (ht < ab) { + ab = ht; + } + if (ht < top) { + top = ht; + } + } } here = i + 1; diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 0fef40beb89f9..720d15aa59805 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -16,6 +16,7 @@ package android.text; +import android.graphics.Bitmap; import android.graphics.Paint; import com.android.internal.util.ArrayUtils; import android.util.Log; @@ -421,11 +422,16 @@ extends Layout // dump(chdirs, n, "final"); - // extra: enforce that all tabs go the primary direction + // extra: enforce that all tabs and surrogate characters go the + // primary direction + // TODO: actually do directions right for surrogates for (int j = 0; j < n; j++) { - if (chs[j] == '\t') + char c = chs[j]; + + if (c == '\t' || (c >= 0xD800 && c <= 0xDFFF)) { chdirs[j] = SOR; + } } // extra: enforce that object replacements go to the @@ -548,16 +554,29 @@ extends Layout char c = chs[j - start]; float before = w; - switch (c) { - case '\n': - break; - - case '\t': + if (c == '\n') { + ; + } else if (c == '\t') { w = Layout.nextTab(sub, start, end, w, null); tab = true; - break; + } else if (c >= 0xD800 && c <= 0xDFFF && j + 1 < next) { + int emoji = Character.codePointAt(chs, j - start); - default: + if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) { + Bitmap bm = EMOJI_FACTORY. + getBitmapFromAndroidPua(emoji); + + if (bm != null) { + w += bm.getWidth(); + tab = true; + j++; + } else { + w += widths[j - start + (end - start)]; + } + } else { + w += widths[j - start + (end - start)]; + } + } else { w += widths[j - start + (end - start)]; } diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java index f7ac522aba6e0..23f3e3c3ece9d 100644 --- a/core/java/android/view/GestureDetector.java +++ b/core/java/android/view/GestureDetector.java @@ -201,8 +201,6 @@ public class GestureDetector { private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); - // TODO make new double-tap timeout, and define its events (i.e. either time - // between down-down or time between up-down) private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout(); // constants for Message.what used by GestureHandler below diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index a856b24c63506..15e7eb2269d3c 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -62,7 +62,8 @@ interface IWindowManager void addAppToken(int addPos, IApplicationToken token, int groupId, int requestedOrientation, boolean fullscreen); void setAppGroupId(IBinder token, int groupId); - Configuration updateOrientationFromAppTokens(IBinder freezeThisOneIfNeeded); + Configuration updateOrientationFromAppTokens(in Configuration currentConfig, + IBinder freezeThisOneIfNeeded); void setAppOrientation(IApplicationToken token, int requestedOrientation); int getAppOrientation(IApplicationToken token); void setFocusedApp(IBinder token, boolean moveFocusNow); diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 430cc71de6108..41779baedaf70 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -234,6 +234,22 @@ public class KeyEvent implements Parcelable { */ public static final int FLAG_KEEP_TOUCH_MODE = 0x4; + /** + * This mask is set if an event was known to come from a trusted part + * of the system. That is, the event is known to come from the user, + * and could not have been spoofed by a third party component. + */ + public static final int FLAG_FROM_SYSTEM = 0x8; + + /** + * This mask is used for compatibility, to identify enter keys that are + * coming from an IME whose enter key has been auto-labelled "next" or + * "done". This allows TextView to dispatch these as normal enter keys + * for old applications, but still do the appropriate action when + * receiving them. + */ + public static final int FLAG_EDITOR_ACTION = 0x10; + /** * Returns the maximum keycode. */ @@ -439,6 +455,22 @@ public class KeyEvent implements Parcelable { mFlags = flags; } + /** + * Make an exact copy of an existing key event. + */ + public KeyEvent(KeyEvent origEvent) { + mDownTime = origEvent.mDownTime; + mEventTime = origEvent.mEventTime; + mAction = origEvent.mAction; + mKeyCode = origEvent.mKeyCode; + mRepeatCount = origEvent.mRepeatCount; + mMetaState = origEvent.mMetaState; + mDeviceId = origEvent.mDeviceId; + mScancode = origEvent.mScancode; + mFlags = origEvent.mFlags; + mCharacters = origEvent.mCharacters; + } + /** * Copy an existing key event, modifying its time and repeat count. * @@ -460,13 +492,27 @@ public class KeyEvent implements Parcelable { mCharacters = origEvent.mCharacters; } + /** + * Create a new key event that is the same as the given one, but whose + * event time and repeat count are replaced with the given value. + * + * @param event The existing event to be copied. This is not modified. + * @param eventTime The new event time + * (in {@link android.os.SystemClock#uptimeMillis}) of the event. + * @param newRepeat The new repeat count of the event. + */ + public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime, + int newRepeat) { + return new KeyEvent(event, eventTime, newRepeat); + } + /** * Copy an existing key event, modifying its action. * * @param origEvent The existing event to be copied. * @param action The new action code of the event. */ - public KeyEvent(KeyEvent origEvent, int action) { + private KeyEvent(KeyEvent origEvent, int action) { mDownTime = origEvent.mDownTime; mEventTime = origEvent.mEventTime; mAction = action; @@ -480,6 +526,30 @@ public class KeyEvent implements Parcelable { // when changing the action. } + /** + * Create a new key event that is the same as the given one, but whose + * action is replaced with the given value. + * + * @param event The existing event to be copied. This is not modified. + * @param action The new action code of the event. + */ + public static KeyEvent changeAction(KeyEvent event, int action) { + return new KeyEvent(event, action); + } + + /** + * Create a new key event that is the same as the given one, but whose + * flags are replaced with the given value. + * + * @param event The existing event to be copied. This is not modified. + * @param flags The new flags constant. + */ + public static KeyEvent changeFlags(KeyEvent event, int flags) { + event = new KeyEvent(event); + event.mFlags = flags; + return event; + } + /** * Don't use in new code, instead explicitly check * {@link #getAction()}. diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index c3e00c40d941c..04447ca4719df 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3409,6 +3409,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (imm != null && (mPrivateFlags & FOCUSED) != 0) { imm.focusOut(this); } + if (mPendingCheckForLongPress != null) { + removeCallbacks(mPendingCheckForLongPress); + } } else if (imm != null && (mPrivateFlags & FOCUSED) != 0) { imm.focusIn(this); } @@ -7656,7 +7659,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { private int mOriginalWindowAttachCount; public void run() { - if (isPressed() && (mParent != null) && hasWindowFocus() + if (isPressed() && (mParent != null) && mOriginalWindowAttachCount == mWindowAttachCount) { if (performLongClick()) { mHasPerformedLongPress = true; diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 6ea7a82f7c92f..f604bc56a06e7 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -19,6 +19,7 @@ package android.view; import android.util.Log; import android.util.DisplayMetrics; import android.content.res.Resources; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.os.Environment; @@ -800,7 +801,7 @@ public class ViewDebug { View view = root.getRootView(); if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; - dumpViewHierarchyWithProperties(group, out, 0); + dumpViewHierarchyWithProperties(group.getContext(), group, out, 0); } out.write("DONE."); out.newLine(); @@ -838,9 +839,9 @@ public class ViewDebug { return view.getClass().getName().equals(className) && view.hashCode() == hashCode; } - private static void dumpViewHierarchyWithProperties(ViewGroup group, + private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group, BufferedWriter out, int level) { - if (!dumpViewWithProperties(group, out, level)) { + if (!dumpViewWithProperties(context, group, out, level)) { return; } @@ -848,14 +849,16 @@ public class ViewDebug { for (int i = 0; i < count; i++) { final View view = group.getChildAt(i); if (view instanceof ViewGroup) { - dumpViewHierarchyWithProperties((ViewGroup) view, out, level + 1); + dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1); } else { - dumpViewWithProperties(view, out, level + 1); + dumpViewWithProperties(context, view, out, level + 1); } } } - private static boolean dumpViewWithProperties(View view, BufferedWriter out, int level) { + private static boolean dumpViewWithProperties(Context context, View view, + BufferedWriter out, int level) { + try { for (int i = 0; i < level; i++) { out.write(' '); @@ -864,7 +867,7 @@ public class ViewDebug { out.write('@'); out.write(Integer.toHexString(view.hashCode())); out.write(' '); - dumpViewProperties(view, out); + dumpViewProperties(context, view, out); out.newLine(); } catch (IOException e) { Log.w("View", "Error while dumping hierarchy tree"); @@ -945,23 +948,26 @@ public class ViewDebug { return methods; } - private static void dumpViewProperties(Object view, BufferedWriter out) throws IOException { - dumpViewProperties(view, out, ""); + private static void dumpViewProperties(Context context, Object view, + BufferedWriter out) throws IOException { + + dumpViewProperties(context, view, out, ""); } - private static void dumpViewProperties(Object view, BufferedWriter out, String prefix) - throws IOException { + private static void dumpViewProperties(Context context, Object view, + BufferedWriter out, String prefix) throws IOException { + Class klass = view.getClass(); do { - exportFields(view, out, klass, prefix); - exportMethods(view, out, klass, prefix); + exportFields(context, view, out, klass, prefix); + exportMethods(context, view, out, klass, prefix); klass = klass.getSuperclass(); } while (klass != Object.class); } - private static void exportMethods(Object view, BufferedWriter out, Class klass, - String prefix) throws IOException { + private static void exportMethods(Context context, Object view, BufferedWriter out, + Class klass, String prefix) throws IOException { final Method[] methods = getExportedPropertyMethods(klass); @@ -976,9 +982,9 @@ public class ViewDebug { if (returnType == int.class) { final ExportedProperty property = sAnnotations.get(method); - if (property.resolveId() && view instanceof View) { + if (property.resolveId() && context != null) { final int id = (Integer) methodValue; - methodValue = resolveId(view, id); + methodValue = resolveId(context, id); } else { final IntToString[] mapping = property.mapping(); if (mapping.length > 0) { @@ -1005,11 +1011,11 @@ public class ViewDebug { final String valuePrefix = prefix + method.getName() + '_'; final String suffix = "()"; - exportUnrolledArray(view, out, property, array, valuePrefix, suffix); + exportUnrolledArray(context, out, property, array, valuePrefix, suffix); } else if (!returnType.isPrimitive()) { final ExportedProperty property = sAnnotations.get(method); if (property.deepExport()) { - dumpViewProperties(methodValue, out, prefix + property.prefix()); + dumpViewProperties(context, methodValue, out, prefix + property.prefix()); continue; } } @@ -1021,8 +1027,9 @@ public class ViewDebug { } } - private static void exportFields(Object view, BufferedWriter out, Class klass, String prefix) - throws IOException { + private static void exportFields(Context context, Object view, BufferedWriter out, + Class klass, String prefix) throws IOException { + final Field[] fields = getExportedPropertyFields(klass); int count = fields.length; @@ -1036,9 +1043,9 @@ public class ViewDebug { if (type == int.class) { final ExportedProperty property = sAnnotations.get(field); - if (property.resolveId() && view instanceof View) { + if (property.resolveId() && context != null) { final int id = field.getInt(view); - fieldValue = resolveId(view, id); + fieldValue = resolveId(context, id); } else { final IntToString[] mapping = property.mapping(); if (mapping.length > 0) { @@ -1063,14 +1070,15 @@ public class ViewDebug { final String valuePrefix = prefix + field.getName() + '_'; final String suffix = ""; - exportUnrolledArray(view, out, property, array, valuePrefix, suffix); + exportUnrolledArray(context, out, property, array, valuePrefix, suffix); // We exit here! return; } else if (!type.isPrimitive()) { final ExportedProperty property = sAnnotations.get(field); if (property.deepExport()) { - dumpViewProperties(field.get(view), out, prefix + property.prefix()); + dumpViewProperties(context, field.get(view), out, + prefix + property.prefix()); continue; } } @@ -1096,7 +1104,7 @@ public class ViewDebug { out.write(' '); } - private static void exportUnrolledArray(Object view, BufferedWriter out, + private static void exportUnrolledArray(Context context, BufferedWriter out, ExportedProperty property, int[] array, String prefix, String suffix) throws IOException { @@ -1106,7 +1114,7 @@ public class ViewDebug { final IntToString[] mapping = property.mapping(); final boolean hasMapping = mapping.length > 0; - final boolean resolveId = property.resolveId() && view instanceof View; + final boolean resolveId = property.resolveId() && context != null; final int valuesCount = array.length; for (int j = 0; j < valuesCount; j++) { @@ -1140,16 +1148,16 @@ public class ViewDebug { } if (resolveId) { - value = (String) resolveId(view, intValue); + value = (String) resolveId(context, intValue); } writeEntry(out, prefix, name, suffix, value); } } - private static Object resolveId(Object view, int id) { + private static Object resolveId(Context context, int id) { Object fieldValue; - final Resources resources = ((View) view).getContext().getResources(); + final Resources resources = context.getResources(); if (id >= 0) { try { fieldValue = resources.getResourceTypeName(id) + '/' + diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index dd2b154c7fbef..fbb4d42b18fb8 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -470,11 +470,20 @@ public final class ViewRoot extends Handler implements ViewParent, void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { synchronized (this) { + int oldSoftInputMode = mWindowAttributes.softInputMode; mWindowAttributes.copyFrom(attrs); if (newView) { mSoftInputMode = attrs.softInputMode; requestLayout(); } + // Don't lose the mode we last auto-computed. + if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) + == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { + mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode + & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) + | (oldSoftInputMode + & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST); + } mWindowAttributesChanged = true; scheduleTraversals(); } @@ -1485,7 +1494,7 @@ public final class ViewRoot extends Handler implements ViewParent, + msg.obj + " to " + mView); deliverKeyEvent((KeyEvent)msg.obj, true); break; - case DISPATCH_POINTER: + case DISPATCH_POINTER: { MotionEvent event = (MotionEvent)msg.obj; boolean didFinish; @@ -1571,7 +1580,7 @@ public final class ViewRoot extends Handler implements ViewParent, // Let the exception fall through -- the looper will catch // it and take care of the bad app for us. } - break; + } break; case DISPATCH_TRACKBALL: deliverTrackballEvent((MotionEvent)msg.obj); break; @@ -1657,12 +1666,19 @@ public final class ViewRoot extends Handler implements ViewParent, case DIE: dispatchDetachedFromWindow(); break; - case DISPATCH_KEY_FROM_IME: + case DISPATCH_KEY_FROM_IME: { if (LOCAL_LOGV) Log.v( "ViewRoot", "Dispatching key " + msg.obj + " from IME to " + mView); + KeyEvent event = (KeyEvent)msg.obj; + if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) { + // The IME is trying to say this event is from the + // system! Bad bad bad! + event = KeyEvent.changeFlags(event, + event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM); + } deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false); - break; + } break; case FINISH_INPUT_CONNECTION: { InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) { diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java index 47b52e4a9ad7e..4230afad7993c 100644 --- a/core/java/android/view/ViewTreeObserver.java +++ b/core/java/android/view/ViewTreeObserver.java @@ -18,7 +18,7 @@ package android.view; import android.graphics.Rect; -import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArrayList; /** * A view tree observer is used to register listeners that can be notified of global @@ -30,12 +30,12 @@ import java.util.ArrayList; * for more information. */ public final class ViewTreeObserver { - private ArrayList mOnGlobalFocusListeners; - private ArrayList mOnGlobalLayoutListeners; - private ArrayList mOnPreDrawListeners; - private ArrayList mOnTouchModeChangeListeners; - private ArrayList mOnComputeInternalInsetsListeners; - private ArrayList mOnScrollChangedListeners; + private CopyOnWriteArrayList mOnGlobalFocusListeners; + private CopyOnWriteArrayList mOnGlobalLayoutListeners; + private CopyOnWriteArrayList mOnPreDrawListeners; + private CopyOnWriteArrayList mOnTouchModeChangeListeners; + private CopyOnWriteArrayList mOnComputeInternalInsetsListeners; + private CopyOnWriteArrayList mOnScrollChangedListeners; private boolean mAlive = true; @@ -283,7 +283,7 @@ public final class ViewTreeObserver { checkIsAlive(); if (mOnGlobalFocusListeners == null) { - mOnGlobalFocusListeners = new ArrayList(); + mOnGlobalFocusListeners = new CopyOnWriteArrayList(); } mOnGlobalFocusListeners.add(listener); @@ -318,7 +318,7 @@ public final class ViewTreeObserver { checkIsAlive(); if (mOnGlobalLayoutListeners == null) { - mOnGlobalLayoutListeners = new ArrayList(); + mOnGlobalLayoutListeners = new CopyOnWriteArrayList(); } mOnGlobalLayoutListeners.add(listener); @@ -352,7 +352,7 @@ public final class ViewTreeObserver { checkIsAlive(); if (mOnPreDrawListeners == null) { - mOnPreDrawListeners = new ArrayList(); + mOnPreDrawListeners = new CopyOnWriteArrayList(); } mOnPreDrawListeners.add(listener); @@ -388,7 +388,7 @@ public final class ViewTreeObserver { checkIsAlive(); if (mOnScrollChangedListeners == null) { - mOnScrollChangedListeners = new ArrayList(); + mOnScrollChangedListeners = new CopyOnWriteArrayList(); } mOnScrollChangedListeners.add(listener); @@ -424,7 +424,7 @@ public final class ViewTreeObserver { checkIsAlive(); if (mOnTouchModeChangeListeners == null) { - mOnTouchModeChangeListeners = new ArrayList(); + mOnTouchModeChangeListeners = new CopyOnWriteArrayList(); } mOnTouchModeChangeListeners.add(listener); @@ -460,7 +460,8 @@ public final class ViewTreeObserver { checkIsAlive(); if (mOnComputeInternalInsetsListeners == null) { - mOnComputeInternalInsetsListeners = new ArrayList(); + mOnComputeInternalInsetsListeners = + new CopyOnWriteArrayList(); } mOnComputeInternalInsetsListeners.add(listener); @@ -518,11 +519,14 @@ public final class ViewTreeObserver { * Notifies registered listeners that focus has changed. */ final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) { - final ArrayList globaFocusListeners = mOnGlobalFocusListeners; - if (globaFocusListeners != null) { - final int count = globaFocusListeners.size(); - for (int i = count - 1; i >= 0; i--) { - globaFocusListeners.get(i).onGlobalFocusChanged(oldFocus, newFocus); + // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to + // perform the dispatching. The iterator is a safe guard against listeners that + // could mutate the list by calling the various add/remove methods. This prevents + // the array from being modified while we iterate it. + final CopyOnWriteArrayList listeners = mOnGlobalFocusListeners; + if (listeners != null) { + for (OnGlobalFocusChangeListener listener : listeners) { + listener.onGlobalFocusChanged(oldFocus, newFocus); } } } @@ -533,11 +537,14 @@ public final class ViewTreeObserver { * not attached to a Window or in the GONE state. */ public final void dispatchOnGlobalLayout() { - final ArrayList globaLayoutListeners = mOnGlobalLayoutListeners; - if (globaLayoutListeners != null) { - final int count = globaLayoutListeners.size(); - for (int i = count - 1; i >= 0; i--) { - globaLayoutListeners.get(i).onGlobalLayout(); + // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to + // perform the dispatching. The iterator is a safe guard against listeners that + // could mutate the list by calling the various add/remove methods. This prevents + // the array from being modified while we iterate it. + final CopyOnWriteArrayList listeners = mOnGlobalLayoutListeners; + if (listeners != null) { + for (OnGlobalLayoutListener listener : listeners) { + listener.onGlobalLayout(); } } } @@ -551,12 +558,15 @@ public final class ViewTreeObserver { * @return True if the current draw should be canceled and resceduled, false otherwise. */ public final boolean dispatchOnPreDraw() { + // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to + // perform the dispatching. The iterator is a safe guard against listeners that + // could mutate the list by calling the various add/remove methods. This prevents + // the array from being modified while we iterate it. boolean cancelDraw = false; - final ArrayList preDrawListeners = mOnPreDrawListeners; - if (preDrawListeners != null) { - final int count = preDrawListeners.size(); - for (int i = count - 1; i >= 0; i--) { - cancelDraw |= !preDrawListeners.get(i).onPreDraw(); + final CopyOnWriteArrayList listeners = mOnPreDrawListeners; + if (listeners != null) { + for (OnPreDrawListener listener : listeners) { + cancelDraw |= !listener.onPreDraw(); } } return cancelDraw; @@ -568,11 +578,15 @@ public final class ViewTreeObserver { * @param inTouchMode True if the touch mode is now enabled, false otherwise. */ final void dispatchOnTouchModeChanged(boolean inTouchMode) { - final ArrayList touchModeListeners = mOnTouchModeChangeListeners; - if (touchModeListeners != null) { - final int count = touchModeListeners.size(); - for (int i = count - 1; i >= 0; i--) { - touchModeListeners.get(i).onTouchModeChanged(inTouchMode); + // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to + // perform the dispatching. The iterator is a safe guard against listeners that + // could mutate the list by calling the various add/remove methods. This prevents + // the array from being modified while we iterate it. + final CopyOnWriteArrayList listeners = + mOnTouchModeChangeListeners; + if (listeners != null) { + for (OnTouchModeChangeListener listener : listeners) { + listener.onTouchModeChanged(inTouchMode); } } } @@ -581,11 +595,14 @@ public final class ViewTreeObserver { * Notifies registered listeners that something has scrolled. */ final void dispatchOnScrollChanged() { - final ArrayList listeners = mOnScrollChangedListeners; - + // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to + // perform the dispatching. The iterator is a safe guard against listeners that + // could mutate the list by calling the various add/remove methods. This prevents + // the array from being modified while we iterate it. + final CopyOnWriteArrayList listeners = mOnScrollChangedListeners; if (listeners != null) { - for (OnScrollChangedListener scl : mOnScrollChangedListeners) { - scl.onScrollChanged(); + for (OnScrollChangedListener listener : listeners) { + listener.onScrollChanged(); } } } @@ -594,7 +611,8 @@ public final class ViewTreeObserver { * Returns whether there are listeners for computing internal insets. */ final boolean hasComputeInternalInsetsListeners() { - final ArrayList listeners = mOnComputeInternalInsetsListeners; + final CopyOnWriteArrayList listeners = + mOnComputeInternalInsetsListeners; return (listeners != null && listeners.size() > 0); } @@ -602,11 +620,15 @@ public final class ViewTreeObserver { * Calls all listeners to compute the current insets. */ final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) { - final ArrayList listeners = mOnComputeInternalInsetsListeners; + // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to + // perform the dispatching. The iterator is a safe guard against listeners that + // could mutate the list by calling the various add/remove methods. This prevents + // the array from being modified while we iterate it. + final CopyOnWriteArrayList listeners = + mOnComputeInternalInsetsListeners; if (listeners != null) { - final int count = listeners.size(); - for (int i = count - 1; i >= 0; i--) { - listeners.get(i).onComputeInternalInsets(inoutInfo); + for (OnComputeInternalInsetsListener listener : listeners) { + listener.onComputeInternalInsets(inoutInfo); } } } diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index b00e565956175..c718bac297761 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -77,13 +77,38 @@ public class EditorInfo implements InputType, Parcelable { */ public static final int IME_ACTION_DONE = 0x00000006; + /** + * Flag of {@link #imeOptions}: used to specify that the IME does not need + * to show its extracted text UI. For input methods that may be fullscreen, + * often when in landscape mode, this allows them to be smaller and let part + * of the application be shown behind. Though there will likely be limited + * access to the application available from the user, it can make the + * experience of a (mostly) fullscreen IME less jarring. Note that when + * this flag is specified the IME may not be set up to be able + * to display text, so it should only be used in situations where this is + * not needed. + */ + public static final int IME_FLAG_NO_EXTRACT_UI = 0x10000000; + /** * Flag of {@link #imeOptions}: used in conjunction with * {@link #IME_MASK_ACTION}, this indicates that the action should not - * be available in-line as the same as a "enter" key. Typically this is + * be available as an accessory button when the input method is full-screen. + * Note that by setting this flag, there can be cases where the action + * is simply never available to the user. Setting this generally means + * that you think showing text being edited is more important than the + * action you have supplied. + */ + public static final int IME_FLAG_NO_ACCESSORY_ACTION = 0x20000000; + + /** + * Flag of {@link #imeOptions}: used in conjunction with + * {@link #IME_MASK_ACTION}, this indicates that the action should not + * be available in-line as a replacement for "enter" key. Typically this is * because the action has such a significant impact or is not recoverable * enough that accidentally hitting it should be avoided, such as sending - * a message. + * a message. Note that {@link android.widget.TextView} will automatically set this + * flag for you on multi-line text views. */ public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000; diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java index dcf68cd9353f3..4528b73aa7889 100644 --- a/core/java/android/webkit/CacheManager.java +++ b/core/java/android/webkit/CacheManager.java @@ -282,9 +282,7 @@ public final class CacheManager { CacheResult result = mDataBase.getCache(url); if (result != null) { if (result.contentLength == 0) { - if (result.httpStatusCode != 301 - && result.httpStatusCode != 302 - && result.httpStatusCode != 307) { + if (!checkCacheRedirect(result.httpStatusCode)) { // this should not happen. If it does, remove it. mDataBase.removeCache(url); return null; @@ -350,6 +348,17 @@ public final class CacheManager { return null; } + // according to the rfc 2616, the 303 response MUST NOT be cached. + if (statusCode == 303) { + return null; + } + + // like the other browsers, do not cache redirects containing a cookie + // header. + if (checkCacheRedirect(statusCode) && !headers.getSetCookie().isEmpty()) { + return null; + } + CacheResult ret = parseHeaders(statusCode, headers, mimeType); if (ret != null) { setupFiles(url, ret); @@ -395,9 +404,7 @@ public final class CacheManager { } cacheRet.contentLength = cacheRet.outFile.length(); - if (cacheRet.httpStatusCode == 301 - || cacheRet.httpStatusCode == 302 - || cacheRet.httpStatusCode == 307) { + if (checkCacheRedirect(cacheRet.httpStatusCode)) { // location is in database, no need to keep the file cacheRet.contentLength = 0; cacheRet.localPath = new String(); @@ -471,6 +478,15 @@ public final class CacheManager { } } + private static boolean checkCacheRedirect(int statusCode) { + if (statusCode == 301 || statusCode == 302 || statusCode == 307) { + // as 303 can't be cached, we do not return true + return true; + } else { + return false; + } + } + @SuppressWarnings("deprecation") private static void setupFiles(String url, CacheResult cacheRet) { if (true) { diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java index 48b9eec2818c2..84dc9f0ae0e81 100644 --- a/core/java/android/webkit/HttpAuthHandler.java +++ b/core/java/android/webkit/HttpAuthHandler.java @@ -80,8 +80,7 @@ public class HttpAuthHandler extends Handler { break; case AUTH_CANCEL: - - mNetwork.resetHandlersAndStopLoading(loader.getFrame()); + loader.handleAuthResponse(null, null); break; } @@ -125,24 +124,6 @@ public class HttpAuthHandler extends Handler { return false; } - /** - * Resets the HTTP-authentication request handler, removes - * all loaders that share the same BrowserFrame - * - * @param frame The browser frame - */ - /* package */ void reset(BrowserFrame frame) { - synchronized (mLoaderQueue) { - ListIterator i = mLoaderQueue.listIterator(0); - while (i.hasNext()) { - LoadListener loader = i.next(); - if (frame == loader.getFrame()) { - i.remove(); - } - } - } - } - /** * Enqueues the loader, if the loader is the only element * in the queue, starts processing the loader diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java index f9fb0b0fccaae..c64200cd5b2a1 100644 --- a/core/java/android/webkit/LoadListener.java +++ b/core/java/android/webkit/LoadListener.java @@ -377,10 +377,6 @@ class LoadListener extends Handler implements EventHandler { } } - // if there is buffered data, commit them in the end - boolean needToCommit = mAuthHeader != null && !mustAuthenticate - && mNativeLoader != 0 && !mDataBuilder.isEmpty(); - // it is only here that we can reset the last mAuthHeader object // (if existed) and start a new one!!! mAuthHeader = null; @@ -415,10 +411,6 @@ class LoadListener extends Handler implements EventHandler { } } commitHeadersCheckRedirect(); - - if (needToCommit) { - commitLoad(); - } } /** @@ -452,6 +444,8 @@ class LoadListener extends Handler implements EventHandler { status.put("minor", minorVersion); status.put("code", code); status.put("reason", reasonPhrase); + // New status means new data. Clear the old. + mDataBuilder.clear(); sendMessageInternal(obtainMessage(MSG_STATUS, status)); } @@ -613,7 +607,6 @@ class LoadListener extends Handler implements EventHandler { // ask for it, so make sure we have a valid CacheLoader // before calling it. if (mCacheLoader != null) { - detachRequestHandle(); mCacheLoader.load(); if (Config.LOGV) { Log.v(LOGTAG, "LoadListener cache load url=" + url()); @@ -738,10 +731,16 @@ class LoadListener extends Handler implements EventHandler { if (mRequestHandle != null) { mRequestHandle.handleSslErrorResponse(proceed); } + if (!proceed) { + // Commit whatever data we have and tear down the loader. + commitLoad(); + tearDown(); + } } /** - * Uses user-supplied credentials to restar a request. + * Uses user-supplied credentials to restart a request. If the credentials + * are null, cancel the request. */ void handleAuthResponse(String username, String password) { if (Config.LOGV) { @@ -780,6 +779,10 @@ class LoadListener extends Handler implements EventHandler { } } } + } else { + // Commit whatever data we have and tear down the loader. + commitLoad(); + tearDown(); } } @@ -944,13 +947,12 @@ class LoadListener extends Handler implements EventHandler { * @return native response pointer */ private int createNativeResponse() { - // The reason we change HTTP_NOT_MODIFIED to HTTP_OK is because we know - // that WebCore never sends the if-modified-since header. Our - // CacheManager does it for us. If the server responds with a 304, then - // we treat it like it was a 200 code and proceed with loading the file - // from the cache. - int statusCode = mStatusCode == HTTP_NOT_MODIFIED - ? HTTP_OK : mStatusCode; + // If WebCore sends if-modified-since, mCacheLoader is null. If + // CacheManager sends it, mCacheLoader is not null. In this case, if the + // server responds with a 304, then we treat it like it was a 200 code + // and proceed with loading the file from the cache. + int statusCode = (mStatusCode == HTTP_NOT_MODIFIED && + mCacheLoader != null) ? HTTP_OK : mStatusCode; // pass content-type content-length and content-encoding final int nativeResponse = nativeCreateResponse( mUrl, statusCode, mStatusText, @@ -1181,8 +1183,6 @@ class LoadListener extends Handler implements EventHandler { // sync. Add 1 to account for the current redirect. mCacheRedirectCount = mRequestHandle.getRedirectCount() + 1; } - // Clear the buffered data since the redirect is valid. - mDataBuilder.clear(); } else { commitHeaders(); commitLoad(); @@ -1197,9 +1197,10 @@ class LoadListener extends Handler implements EventHandler { /** * Parses the content-type header. + * The first part only allows '-' if it follows x or X. */ private static final Pattern CONTENT_TYPE_PATTERN = - Pattern.compile("^([a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$"); + Pattern.compile("^((?:[xX]-)?[a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$"); private void parseContentTypeHeader(String contentType) { if (Config.LOGV) { diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java index c9cc20817c4fd..85c2275df9916 100644 --- a/core/java/android/webkit/MimeTypeMap.java +++ b/core/java/android/webkit/MimeTypeMap.java @@ -496,6 +496,7 @@ public /* package */ class MimeTypeMap { sMimeTypeMap.loadEntry("video/x-msvideo", "avi", false); sMimeTypeMap.loadEntry("video/x-sgi-movie", "movie", false); sMimeTypeMap.loadEntry("x-conference/x-cooltalk", "ice", false); + sMimeTypeMap.loadEntry("x-epoc/x-sisx-app", "sisx", false); } return sMimeTypeMap; diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java index 74622b3b3883e..6fa07753dea33 100644 --- a/core/java/android/webkit/Network.java +++ b/core/java/android/webkit/Network.java @@ -260,24 +260,6 @@ class Network { mProxyPassword = proxyPassword; } - /** - * If we need to stop loading done in a handler (here, browser frame), we - * send a message to the handler to stop loading, and remove all loaders - * that share the same CallbackProxy in question from all local - * handlers (such as ssl-error and http-authentication handler). - * @param proxy The CallbackProxy responsible for cancelling the current - * load. - */ - public void resetHandlersAndStopLoading(BrowserFrame frame) { - if (Config.LOGV) { - Log.v(LOGTAG, "Network.resetHandlersAndStopLoading()"); - } - - frame.stopLoading(); - mSslErrorHandler.reset(frame); - mHttpAuthHandler.reset(frame); - } - /** * Saves the state of network handlers (user SSL and HTTP-authentication * preferences). diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java index 115434a98d032..2e2fa12052abb 100644 --- a/core/java/android/webkit/SslErrorHandler.java +++ b/core/java/android/webkit/SslErrorHandler.java @@ -117,20 +117,6 @@ public class SslErrorHandler extends Handler { mSslPrefTable.clear(); } - /** - * Resets the SSL error handler, removes all loaders that - * share the same BrowserFrame. - */ - /* package */ synchronized void reset(BrowserFrame frame) { - ListIterator i = mLoaderQueue.listIterator(0); - while (i.hasNext()) { - LoadListener loader = i.next(); - if (frame == loader.getFrame()) { - i.remove(); - } - } - } - /** * Handles SSL error(s) on the way up to the user. */ @@ -244,12 +230,8 @@ public class SslErrorHandler extends Handler { primary > mSslPrefTable.getInt(host)) { mSslPrefTable.putInt(host, new Integer(primary)); } - - loader.handleSslErrorResponse(proceed); - } else { - loader.handleSslErrorResponse(proceed); - mNetwork.resetHandlersAndStopLoading(loader.getFrame()); } + loader.handleSslErrorResponse(proceed); } } } diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 65544d450f368..025e6bb819cca 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -153,6 +153,7 @@ public class WebSettings { private boolean mNeedInitialFocus = true; private boolean mNavDump = false; private boolean mSupportZoom = true; + private boolean mBuiltInZoomControls = false; private boolean mAllowFileAccess = true; // Class to handle messages before WebCore is ready. @@ -363,6 +364,20 @@ public class WebSettings { return mSupportZoom; } + /** + * Sets whether the zoom mechanism built into WebView is used. + */ + public void setBuiltInZoomControls(boolean enabled) { + mBuiltInZoomControls = enabled; + } + + /** + * Returns true if the zoom mechanism built into WebView is being used. + */ + public boolean getBuiltInZoomControls() { + return mBuiltInZoomControls; + } + /** * Enable or disable file access within WebView. File access is enabled by * default. diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 753267fd737a9..3205820361c3d 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -56,17 +56,20 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewTreeObserver; +import android.view.animation.AlphaAnimation; import android.view.inputmethod.InputMethodManager; import android.webkit.TextDialog.AutoCompleteAdapter; import android.webkit.WebViewCore.EventHub; import android.widget.AbsoluteLayout; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ListView; import android.widget.Scroller; import android.widget.Toast; import android.widget.ZoomButtonsController; +import android.widget.ZoomControls; import android.widget.AdapterView.OnItemClickListener; import java.io.File; @@ -85,6 +88,9 @@ import java.util.List; * It uses the WebKit rendering engine to display * web pages and includes methods to navigate forward and backward * through a history, zoom in and out, perform text searches and more.

+ *

To enable the built-in zoom, set + * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)} + * (introduced in API version 3). *

Note that, in order for your Activity to access the Internet and load web pages * in a WebView, you must add the INTERNET permissions to your * Android Manifest file:

@@ -106,6 +112,57 @@ public class WebView extends AbsoluteLayout static final boolean DEBUG = false; static final boolean LOGV_ENABLED = DEBUG ? Config.LOGD : Config.LOGV; + private class ExtendedZoomControls extends FrameLayout { + public ExtendedZoomControls(Context context, AttributeSet attrs) { + super(context, attrs); + LayoutInflater inflater = (LayoutInflater) + context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(com.android.internal.R.layout.zoom_magnify, this, true); + mZoomControls = (ZoomControls) findViewById(com.android.internal.R.id.zoomControls); + mZoomMagnify = (ImageView) findViewById(com.android.internal.R.id.zoomMagnify); + } + + public void show(boolean showZoom, boolean canZoomOut) { + mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE); + mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE); + fade(View.VISIBLE, 0.0f, 1.0f); + } + + public void hide() { + fade(View.GONE, 1.0f, 0.0f); + } + + private void fade(int visibility, float startAlpha, float endAlpha) { + AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha); + anim.setDuration(500); + startAnimation(anim); + setVisibility(visibility); + } + + public void setIsZoomMagnifyEnabled(boolean isEnabled) { + mZoomMagnify.setEnabled(isEnabled); + } + + public boolean hasFocus() { + return mZoomControls.hasFocus() || mZoomMagnify.hasFocus(); + } + + public void setOnZoomInClickListener(OnClickListener listener) { + mZoomControls.setOnZoomInClickListener(listener); + } + + public void setOnZoomOutClickListener(OnClickListener listener) { + mZoomControls.setOnZoomOutClickListener(listener); + } + + public void setOnZoomMagnifyClickListener(OnClickListener listener) { + mZoomMagnify.setOnClickListener(listener); + } + + ZoomControls mZoomControls; + ImageView mZoomMagnify; + } + /** * Transportation object for returning WebView across thread boundaries. */ @@ -232,6 +289,9 @@ public class WebView extends AbsoluteLayout private static final int LONG_PRESS_TIMEOUT = 1000; // needed to avoid flinging after a pause of no movement private static final int MIN_FLING_TIME = 250; + // The time that the Zoom Controls are visible before fading away + private static final long ZOOM_CONTROLS_TIMEOUT = + ViewConfiguration.getZoomControlsTimeout(); // The amount of content to overlap between two screens when going through // pages with the space bar, in pixels. private static final int PAGE_SCROLL_OVERLAP = 24; @@ -472,6 +532,10 @@ public class WebView extends AbsoluteLayout } } + // The View containing the zoom controls + private ExtendedZoomControls mZoomControls; + private Runnable mZoomControlRunnable; + private ZoomButtonsController mZoomButtonsController; private ImageView mZoomOverviewButton; private ImageView mZoomFitPageButton; @@ -484,11 +548,6 @@ public class WebView extends AbsoluteLayout private ZoomButtonsController.OnZoomListener mZoomListener = new ZoomButtonsController.OnZoomListener() { - public void onCenter(int x, int y) { - // Don't translate when the control is invoked, hence we do nothing - // in this callback - } - public void onVisibilityChanged(boolean visible) { if (visible) { switchOutDrawHistory(); @@ -582,10 +641,26 @@ public class WebView extends AbsoluteLayout } private void updateZoomButtonsEnabled() { - mZoomButtonsController.setZoomInEnabled(mActualScale < mMaxZoomScale); - mZoomButtonsController.setZoomOutEnabled(mActualScale > mMinZoomScale); - mZoomFitPageButton.setEnabled(mActualScale != 1); - mZoomOverviewButton.setEnabled(canZoomScrollOut()); + boolean canZoomIn = mActualScale < mMaxZoomScale; + boolean canZoomOut = mActualScale > mMinZoomScale; + if (!canZoomIn && !canZoomOut) { + // Hide the zoom in and out buttons, as well as the fit to page + // button, if the page cannot zoom + mZoomButtonsController.getZoomControls().setVisibility(View.GONE); + mZoomFitPageButton.setVisibility(View.GONE); + } else { + // Bring back the hidden zoom controls. + mZoomButtonsController.getZoomControls() + .setVisibility(View.VISIBLE); + mZoomFitPageButton.setVisibility(View.VISIBLE); + // Set each one individually, as a page may be able to zoom in + // or out. + mZoomButtonsController.setZoomInEnabled(canZoomIn); + mZoomButtonsController.setZoomOutEnabled(canZoomOut); + mZoomFitPageButton.setEnabled(mActualScale != 1); + } + mZoomOverviewButton.setVisibility(canZoomScrollOut() ? View.VISIBLE: + View.GONE); } private void init() { @@ -1332,7 +1407,13 @@ public class WebView extends AbsoluteLayout return; } clearTextEntry(); - mZoomButtonsController.setVisible(true); + if (getSettings().getBuiltInZoomControls()) { + mZoomButtonsController.setVisible(true); + } else { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + } } /** @@ -2535,8 +2616,17 @@ public class WebView extends AbsoluteLayout private void startZoomScrollOut() { setHorizontalScrollBarEnabled(false); setVerticalScrollBarEnabled(false); - if (mZoomButtonsController.isVisible()) { - mZoomButtonsController.setVisible(false); + if (getSettings().getBuiltInZoomControls()) { + if (mZoomButtonsController.isVisible()) { + mZoomButtonsController.setVisible(false); + } + } else { + if (mZoomControlRunnable != null) { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + } + if (mZoomControls != null) { + mZoomControls.hide(); + } } int width = getViewWidth(); int height = getViewHeight(); @@ -3206,7 +3296,6 @@ public class WebView extends AbsoluteLayout // Clean up the zoom controller mZoomButtonsController.setVisible(false); - ZoomButtonsController.finishZoomTutorial(mContext, false); } // Implementation for OnHierarchyChangeListener @@ -3255,7 +3344,7 @@ public class WebView extends AbsoluteLayout // false for the first parameter } } else { - if (!mZoomButtonsController.isVisible()) { + if (getSettings().getBuiltInZoomControls() && !mZoomButtonsController.isVisible()) { /* * The zoom controls come in their own window, so our window * loses focus. Our policy is to not draw the focus ring if @@ -3527,7 +3616,9 @@ public class WebView extends AbsoluteLayout mWebViewCore .sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0); } - if (getSettings().supportZoom() + WebSettings settings = getSettings(); + if (settings.supportZoom() + && settings.getBuiltInZoomControls() && !mZoomButtonsController.isVisible() && (canZoomScrollOut() || mMinZoomScale < mMaxZoomScale)) { @@ -3594,6 +3685,21 @@ public class WebView extends AbsoluteLayout mLastTouchTime = eventTime; mUserScroll = true; } + + if (!getSettings().getBuiltInZoomControls()) { + boolean showPlusMinus = mMinZoomScale < mMaxZoomScale; + boolean showMagnify = canZoomScrollOut(); + if (mZoomControls != null && (showPlusMinus || showMagnify)) { + if (mZoomControls.getVisibility() == View.VISIBLE) { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + } else { + mZoomControls.show(showPlusMinus, showMagnify); + } + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + } + } + if (done) { // return false to indicate that we can't pan out of the // view space @@ -4050,18 +4156,83 @@ public class WebView extends AbsoluteLayout } } - // TODO: deprecate /** * Returns a view containing zoom controls i.e. +/- buttons. The caller is * in charge of installing this view to the view hierarchy. This view will * become visible when the user starts scrolling via touch and fade away if * the user does not interact with it. *

- * From 1.5, WebView change to use ZoomButtonsController. This will return - * an invisible dummy view for backwards compatibility. + * API version 3 introduces a built-in zoom mechanism that is shown + * automatically by the MapView. This is the preferred approach for + * showing the zoom UI. + * + * @deprecated The built-in zoom mechanism is preferred, see + * {@link WebSettings#setBuiltInZoomControls(boolean)}. */ + @Deprecated public View getZoomControls() { - return mZoomButtonsController.getDummyZoomControls(); + if (!getSettings().supportZoom()) { + Log.w(LOGTAG, "This WebView doesn't support zoom."); + return null; + } + if (mZoomControls == null) { + mZoomControls = createZoomControls(); + + /* + * need to be set to VISIBLE first so that getMeasuredHeight() in + * {@link #onSizeChanged()} can return the measured value for proper + * layout. + */ + mZoomControls.setVisibility(View.VISIBLE); + mZoomControlRunnable = new Runnable() { + public void run() { + + /* Don't dismiss the controls if the user has + * focus on them. Wait and check again later. + */ + if (!mZoomControls.hasFocus()) { + mZoomControls.hide(); + } else { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + } + } + }; + } + return mZoomControls; + } + + private ExtendedZoomControls createZoomControls() { + ExtendedZoomControls zoomControls = new ExtendedZoomControls(mContext + , null); + zoomControls.setOnZoomInClickListener(new OnClickListener() { + public void onClick(View v) { + // reset time out + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + zoomIn(); + } + }); + zoomControls.setOnZoomOutClickListener(new OnClickListener() { + public void onClick(View v) { + // reset time out + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + zoomOut(); + } + }); + zoomControls.setOnZoomMagnifyClickListener(new OnClickListener() { + public void onClick(View v) { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + zoomScrollOut(); + } + }); + return zoomControls; } /** @@ -4070,7 +4241,7 @@ public class WebView extends AbsoluteLayout * * @return The instance of {@link ZoomButtonsController} used by this class, * or null if it is unavailable. - * @hide pending API council + * @hide */ public ZoomButtonsController getZoomButtonsController() { return mZoomButtonsController; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index bd4bba8f57bff..965d900f32ac6 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -905,10 +905,7 @@ public abstract class AbsListView extends AdapterView implements Te ((Filterable) getAdapter()).getFilter() == null) { return false; } - final Context context = mContext; - final InputMethodManager inputManager = (InputMethodManager) - context.getSystemService(Context.INPUT_METHOD_SERVICE); - return !inputManager.isFullscreenMode(); + return true; } /** @@ -2904,7 +2901,7 @@ public abstract class AbsListView extends AdapterView implements Te KeyEvent forwardEvent = event; if (forwardEvent.getRepeatCount() > 0) { - forwardEvent = new KeyEvent(event, event.getEventTime(), 0); + forwardEvent = KeyEvent.changeTimeRepeat(event, event.getEventTime(), 0); } int action = event.getAction(); @@ -2967,6 +2964,7 @@ public abstract class AbsListView extends AdapterView implements Te // want to figure out why this is. mTextFilter.setRawInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_FILTER); + mTextFilter.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); mTextFilter.addTextChangedListener(this); p.setFocusable(false); p.setTouchable(false); diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 1d553f1d2b297..04cb8a0159442 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -164,7 +164,7 @@ public abstract class AbsSeekBar extends ProgressBar { void onProgressRefresh(float scale, boolean fromUser) { Drawable thumb = mThumb; if (thumb != null) { - setThumbPos(getWidth(), getHeight(), thumb, scale, Integer.MIN_VALUE); + setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE); /* * Since we draw translated, the drawable's bounds that it signals * for invalidation won't be the actual bounds we want invalidated, @@ -189,7 +189,7 @@ public abstract class AbsSeekBar extends ProgressBar { if (thumbHeight > trackHeight) { if (thumb != null) { - setThumbPos(w, h, thumb, scale, 0); + setThumbPos(w, thumb, scale, 0); } int gapForCenteringTrack = (thumbHeight - trackHeight) / 2; if (d != null) { @@ -206,16 +206,15 @@ public abstract class AbsSeekBar extends ProgressBar { } int gap = (trackHeight - thumbHeight) / 2; if (thumb != null) { - setThumbPos(w, h, thumb, scale, gap); + setThumbPos(w, thumb, scale, gap); } } } /** * @param gap If set to {@link Integer#MIN_VALUE}, this will be ignored and - * the old vertical bounds will be used. */ - private void setThumbPos(int w, int h, Drawable thumb, float scale, int gap) { + private void setThumbPos(int w, Drawable thumb, float scale, int gap) { int available = w - mPaddingLeft - mPaddingRight; int thumbWidth = thumb.getIntrinsicWidth(); int thumbHeight = thumb.getIntrinsicHeight(); @@ -353,6 +352,12 @@ public abstract class AbsSeekBar extends ProgressBar { void onStopTrackingTouch() { } + /** + * Called when the user changes the seekbar's progress by using a key event. + */ + void onKeyChange() { + } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { int progress = getProgress(); @@ -361,11 +366,13 @@ public abstract class AbsSeekBar extends ProgressBar { case KeyEvent.KEYCODE_DPAD_LEFT: if (progress <= 0) break; setProgress(progress - mKeyProgressIncrement, true); + onKeyChange(); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (progress >= getMax()) break; setProgress(progress + mKeyProgressIncrement, true); + onKeyChange(); return true; } diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java index 8aafee2118f9c..2bb716cbf1510 100644 --- a/core/java/android/widget/FrameLayout.java +++ b/core/java/android/widget/FrameLayout.java @@ -56,6 +56,7 @@ public class FrameLayout extends ViewGroup { private final Rect mSelfBounds = new Rect(); private final Rect mOverlayBounds = new Rect(); private int mForegroundGravity = Gravity.FILL; + private boolean mForegroundInPadding = true; public FrameLayout(Context context) { super(context); @@ -71,6 +72,9 @@ public class FrameLayout extends ViewGroup { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.FrameLayout, defStyle, 0); + mForegroundGravity = a.getInt( + com.android.internal.R.styleable.FrameLayout_foregroundGravity, mForegroundGravity); + final Drawable d = a.getDrawable(com.android.internal.R.styleable.FrameLayout_foreground); if (d != null) { setForeground(d); @@ -80,8 +84,8 @@ public class FrameLayout extends ViewGroup { setMeasureAllChildren(true); } - mForegroundGravity = a.getInt(com.android.internal.R.styleable.FrameLayout_foregroundGravity, - mForegroundGravity); + mForegroundInPadding = a.getBoolean( + com.android.internal.R.styleable.FrameLayout_foregroundInsidePadding, true); a.recycle(); } @@ -105,6 +109,23 @@ public class FrameLayout extends ViewGroup { } mForegroundGravity = foregroundGravity; + + + if (mForegroundGravity == Gravity.FILL && mForeground != null) { + Rect padding = new Rect(); + if (mForeground.getPadding(padding)) { + mForegroundPaddingLeft = padding.left; + mForegroundPaddingTop = padding.top; + mForegroundPaddingRight = padding.right; + mForegroundPaddingBottom = padding.bottom; + } + } else { + mForegroundPaddingLeft = 0; + mForegroundPaddingTop = 0; + mForegroundPaddingRight = 0; + mForegroundPaddingBottom = 0; + } + requestLayout(); } } @@ -167,12 +188,14 @@ public class FrameLayout extends ViewGroup { if (drawable.isStateful()) { drawable.setState(getDrawableState()); } - Rect padding = new Rect(); - if (drawable.getPadding(padding)) { - mForegroundPaddingLeft = padding.left; - mForegroundPaddingTop = padding.top; - mForegroundPaddingRight = padding.right; - mForegroundPaddingBottom = padding.bottom; + if (mForegroundGravity == Gravity.FILL) { + Rect padding = new Rect(); + if (drawable.getPadding(padding)) { + mForegroundPaddingLeft = padding.left; + mForegroundPaddingTop = padding.top; + mForegroundPaddingRight = padding.right; + mForegroundPaddingBottom = padding.bottom; + } } } else { setWillNotDraw(true); @@ -309,10 +332,14 @@ public class FrameLayout extends ViewGroup { final Rect selfBounds = mSelfBounds; final Rect overlayBounds = mOverlayBounds; - selfBounds.set(0, 0, w, h); + if (mForegroundInPadding) { + selfBounds.set(0, 0, w, h); + } else { + selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom); + } + Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(), foreground.getIntrinsicHeight(), selfBounds, overlayBounds); - foreground.setBounds(overlayBounds); } } diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java index 227fb9571d2f7..a2ec83fb49341 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -405,6 +405,8 @@ public class MediaController extends FrameLayout { return super.dispatchKeyEvent(event); } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) { hide(); + + return true; } else { show(sDefaultTimeout); } diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index a4f729f6f6eb4..f864690b60f82 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1125,17 +1125,16 @@ public class PopupWindow { } /** - *

Updates the position and the dimension of the popup window. Width and - * height can be set to -1 to update location only. Calling this function - * also updates the window with the current popup state as - * described for {@link #update()}.

+ *

Updates the position and the dimension of the popup window. Calling this + * function also updates the window with the current popup state as described + * for {@link #update()}.

* * @param anchor the popup's anchor view * @param width the new width, can be -1 to ignore * @param height the new height, can be -1 to ignore */ public void update(View anchor, int width, int height) { - update(anchor, 0, 0, width, height); + update(anchor, false, 0, 0, true, width, height); } /** @@ -1153,31 +1152,44 @@ public class PopupWindow { * @param height the new height, can be -1 to ignore */ public void update(View anchor, int xoff, int yoff, int width, int height) { + update(anchor, true, xoff, yoff, true, width, height); + } + + private void update(View anchor, boolean updateLocation, int xoff, int yoff, + boolean updateDimension, int width, int height) { + if (!isShowing() || mContentView == null) { return; } WeakReference oldAnchor = mAnchor; if (oldAnchor == null || oldAnchor.get() != anchor || - mAnchorXoff != xoff || mAnchorYoff != yoff) { + (updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff))) { registerForScrollChanged(anchor, xoff, yoff); } WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams(); - if (width == -1) { - width = mPopupWidth; - } else { - mPopupWidth = width; + if (updateDimension) { + if (width == -1) { + width = mPopupWidth; + } else { + mPopupWidth = width; + } + if (height == -1) { + height = mPopupHeight; + } else { + mPopupHeight = height; + } } - if (height == -1) { - height = mPopupHeight; + + if (updateLocation) { + mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff); } else { - mPopupHeight = height; + mAboveAnchor = findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff); } - - mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff); + update(p.x, p.y, width, height); } diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java index ad5ca07125a45..1800c5a01b9a8 100644 --- a/core/java/android/widget/RatingBar.java +++ b/core/java/android/widget/RatingBar.java @@ -296,7 +296,13 @@ public class RatingBar extends AbsSeekBar { dispatchRatingChange(true); } } - + + @Override + void onKeyChange() { + super.onKeyChange(); + dispatchRatingChange(true); + } + void dispatchRatingChange(boolean fromUser) { if (mOnRatingBarChangeListener != null) { mOnRatingBarChangeListener.onRatingChanged(this, getRating(), diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 52c421c7dd945..c4f0abdd85a6e 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -821,7 +821,10 @@ public class RelativeLayout extends ViewGroup { @ViewDebug.IntToString(from = CENTER_VERTICAL, to = "centerVertical"), @ViewDebug.IntToString(from = LEFT_OF, to = "leftOf"), @ViewDebug.IntToString(from = RIGHT_OF, to = "rightOf") - }, mapping = { @ViewDebug.IntToString(from = TRUE, to = "true") }) + }, mapping = { + @ViewDebug.IntToString(from = TRUE, to = "true"), + @ViewDebug.IntToString(from = 0, to = "NO_ID") + }) private int[] mRules = new int[VERB_COUNT]; private int mLeft, mTop, mRight, mBottom; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 7b62b50ce31f8..136752b9f3a2f 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -224,7 +224,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private CharSequence mError; private boolean mErrorWasChanged; - private PopupWindow mPopup; + private ErrorPopup mPopup; /** * This flag is set if the TextView tries to display an error before it * is attached to the window (so its position is still unknown). @@ -3039,12 +3039,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return; } } - } - if (ict != null || !shouldAdvanceFocusOnEnter()) { + // This is the handling for some default action. // Note that for backwards compatibility we don't do this // default handling if explicit ime options have not been given, - // to instead turn this into the normal enter key codes that an + // instead turning this into the normal enter key codes that an // app may be expecting. if (actionCode == EditorInfo.IME_ACTION_NEXT) { View v = focusSearch(FOCUS_DOWN); @@ -3066,15 +3065,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } Handler h = getHandler(); - long eventTime = SystemClock.uptimeMillis(); - h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, - new KeyEvent(eventTime, eventTime, - KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0, - KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); - h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, - new KeyEvent(SystemClock.uptimeMillis(), eventTime, - KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0, - KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); + if (h != null) { + long eventTime = SystemClock.uptimeMillis(); + h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, + new KeyEvent(eventTime, eventTime, + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0, + KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE + | KeyEvent.FLAG_EDITOR_ACTION))); + h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, + new KeyEvent(SystemClock.uptimeMillis(), eventTime, + KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0, + KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE + | KeyEvent.FLAG_EDITOR_ACTION))); + } } /** @@ -3222,25 +3225,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final TextView err = (TextView) inflater.inflate(com.android.internal.R.layout.textview_hint, null); - mPopup = new PopupWindow(err, 200, 50) { - private boolean mAbove = false; - - @Override - public void update(int x, int y, int w, int h, boolean force) { - super.update(x, y, w, h, force); - - boolean above = isAboveAnchor(); - if (above != mAbove) { - mAbove = above; - - if (above) { - err.setBackgroundResource(com.android.internal.R.drawable.popup_inline_error_above); - } else { - err.setBackgroundResource(com.android.internal.R.drawable.popup_inline_error); - } - } - } - }; + mPopup = new ErrorPopup(err, 200, 50); mPopup.setFocusable(false); // The user is entering text, so the input method is needed. We // don't want the popup to be displayed on top of it. @@ -3252,6 +3237,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener tv.setText(mError); mPopup.showAsDropDown(this, getErrorX(), getErrorY()); + mPopup.fixDirection(mPopup.isAboveAnchor()); + } + + private static class ErrorPopup extends PopupWindow { + private boolean mAbove = false; + private TextView mView; + + ErrorPopup(TextView v, int width, int height) { + super(v, width, height); + mView = v; + } + + void fixDirection(boolean above) { + mAbove = above; + + if (above) { + mView.setBackgroundResource(com.android.internal.R.drawable.popup_inline_error_above); + } else { + mView.setBackgroundResource(com.android.internal.R.drawable.popup_inline_error); + } + } + + @Override + public void update(int x, int y, int w, int h, boolean force) { + super.update(x, y, w, h, force); + + boolean above = isAboveAnchor(); + if (above != mAbove) { + fixDirection(above); + } + } } /** @@ -4001,7 +4017,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { - KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN); + KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN); int which = doKeyDown(keyCode, down, event); if (which == 0) { @@ -4020,7 +4036,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // of down and up events until we have done the complete repeatCount. // It would be nice if those interfaces had an onKeyMultiple() method, // but adding that is a more complicated change. - KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP); + KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP); if (which == 1) { mInput.onKeyUp(this, (Editable)mText, keyCode, up); while (--repeatCount > 0) { @@ -4069,19 +4085,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } - private boolean isInterestingEnter(KeyEvent event) { - if ((event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 && - mInputContentType != null && - (mInputContentType.imeOptions & - EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) { - // If this enter key came from a soft keyboard, and the - // text editor has been configured to not do a default - // action for software enter keys, then we aren't interested. - return false; - } - return true; - } - private int doKeyDown(int keyCode, KeyEvent event, KeyEvent otherEvent) { if (!isEnabled()) { return 0; @@ -4089,18 +4092,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener switch (keyCode) { case KeyEvent.KEYCODE_ENTER: - if (!isInterestingEnter(event)) { - // Ignore enter key we aren't interested in. - return -1; + // If ALT modifier is held, then we always insert a + // newline character. + if ((event.getMetaState()&KeyEvent.META_ALT_ON) == 0) { + + // When mInputContentType is set, we know that we are + // running in a "modern" cupcake environment, so don't need + // to worry about the application trying to capture + // enter key events. + if (mInputContentType != null) { + + // If there is an action listener, given them a + // chance to consume the event. + if (mInputContentType.onEditorActionListener != null && + mInputContentType.onEditorActionListener.onEditorAction( + this, EditorInfo.IME_NULL, event)) { + mInputContentType.enterDown = true; + // We are consuming the enter key for them. + return -1; + } + } + + // If our editor should move focus when enter is pressed, or + // this is a generated event from an IME action button, then + // don't let it be inserted into the text. + if ((event.getFlags()&KeyEvent.FLAG_EDITOR_ACTION) != 0 + || shouldAdvanceFocusOnEnter()) { + return -1; + } } - if ((event.getMetaState()&KeyEvent.META_ALT_ON) == 0 - && mInputContentType != null - && mInputContentType.onEditorActionListener != null) { - mInputContentType.enterDown = true; - // We are consuming the enter key for them. - return -1; - } - // fall through... + break; + case KeyEvent.KEYCODE_DPAD_CENTER: if (shouldAdvanceFocusOnEnter()) { return 0; @@ -4215,7 +4237,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (shouldAdvanceFocusOnEnter()) { + if ((event.getFlags()&KeyEvent.FLAG_EDITOR_ACTION) != 0 + || shouldAdvanceFocusOnEnter()) { /* * If there is a click listener, just call through to * super, which will invoke it. @@ -4243,7 +4266,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener super.onKeyUp(keyCode, event); return true; } else if ((event.getFlags() - & KeyEvent.FLAG_SOFT_KEYBOARD) != 0) { + & KeyEvent.FLAG_EDITOR_ACTION) != 0) { // No target for next focus, but make sure the IME // if this came from it. InputMethodManager imm = InputMethodManager.peekInstance(); @@ -4302,6 +4325,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION; } } + if ((outAttrs.inputType & (InputType.TYPE_MASK_CLASS + | InputType.TYPE_TEXT_FLAG_MULTI_LINE)) + == (InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_FLAG_MULTI_LINE)) { + // Multi-line text editors should always show an enter key. + outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION; + } outAttrs.hintText = mHint; if (mText instanceof Editable) { InputConnection ic = new EditableInputConnection(this); diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java index 0df919d02a5f3..c5fa18c95f059 100644 --- a/core/java/android/widget/ZoomButton.java +++ b/core/java/android/widget/ZoomButton.java @@ -19,15 +19,11 @@ package android.widget; import android.content.Context; import android.os.Handler; import android.util.AttributeSet; -import android.view.GestureDetector; -import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.GestureDetector.SimpleOnGestureListener; import android.view.View.OnLongClickListener; - public class ZoomButton extends ImageButton implements OnLongClickListener { private final Handler mHandler; @@ -39,7 +35,6 @@ public class ZoomButton extends ImageButton implements OnLongClickListener { } } }; - private final GestureDetector mGestureDetector; private long mZoomSpeed = 1000; private boolean mIsInLongpress; @@ -55,19 +50,11 @@ public class ZoomButton extends ImageButton implements OnLongClickListener { public ZoomButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mHandler = new Handler(); - mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() { - @Override - public void onLongPress(MotionEvent e) { - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - onLongClick(ZoomButton.this); - } - }); setOnLongClickListener(this); } @Override public boolean onTouchEvent(MotionEvent event) { - mGestureDetector.onTouchEvent(event); if ((event.getAction() == MotionEvent.ACTION_CANCEL) || (event.getAction() == MotionEvent.ACTION_UP)) { mIsInLongpress = false; diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java index 4daa41949330b..d9fb78b81d385 100644 --- a/core/java/android/widget/ZoomButtonsController.java +++ b/core/java/android/widget/ZoomButtonsController.java @@ -16,23 +16,15 @@ package android.widget; -import android.app.AlertDialog; -import android.app.Dialog; import android.content.BroadcastReceiver; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.graphics.Canvas; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Handler; import android.os.Message; -import android.os.SystemClock; -import android.provider.Settings; import android.util.Log; -import android.view.GestureDetector; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -42,7 +34,6 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewRoot; -import android.view.Window; import android.view.WindowManager; import android.view.View.OnClickListener; import android.view.WindowManager.LayoutParams; @@ -51,29 +42,33 @@ import android.view.WindowManager.LayoutParams; * Implementation notes: * - The zoom controls are displayed in their own window. * (Easier for the client and better performance) - * - This window is not touchable, and by default is not focusable. - * - To make the buttons clickable, it attaches a OnTouchListener to the owner - * view and does the hit detection locally. + * - This window is never touchable, and by default is not focusable. + * Its rect is quite big (fills horizontally) but has empty space between the + * edges and center. Touches there should be given to the owner. Instead of + * having the window touchable and dispatching these empty touch events to the + * owner, we set the window to not touchable and steal events from owner + * via onTouchListener. + * - To make the buttons clickable, it attaches an OnTouchListener to the owner + * view and does the hit detection locally (attaches when visible, detaches when invisible). * - When it is focusable, it forwards uninteresting events to the owner view's * view hierarchy. */ /** * The {@link ZoomButtonsController} handles showing and hiding the zoom - * controls relative to an owner view. It also gives the client access to the - * zoom controls container, allowing for additional accessory buttons to be - * shown in the zoom controls window. + * controls and positioning it relative to an owner view. It also gives the + * client access to the zoom controls container, allowing for additional + * accessory buttons to be shown in the zoom controls window. *

- * Typical usage involves the client using the {@link GestureDetector} to - * forward events from - * {@link GestureDetector.OnDoubleTapListener#onDoubleTapEvent(MotionEvent)} to - * {@link #handleDoubleTapEvent(MotionEvent)}. Also, whenever the owner cannot - * be zoomed further, the client should update + * Typically, clients should call {@link #setVisible(boolean) setVisible(true)} + * on a touch down or move (no need to call {@link #setVisible(boolean) + * setVisible(false)} since it will time out on its own). Also, whenever the + * owner cannot be zoomed further, the client should update * {@link #setZoomInEnabled(boolean)} and {@link #setZoomOutEnabled(boolean)}. *

* If you are using this with a custom View, please call * {@link #setVisible(boolean) setVisible(false)} from the * {@link View#onDetachedFromWindow}. - * + * * @hide */ public class ZoomButtonsController implements View.OnTouchListener { @@ -88,6 +83,7 @@ public class ZoomButtonsController implements View.OnTouchListener { private Context mContext; private WindowManager mWindowManager; + private boolean mAutoDismissControls = true; /** * The view that is being zoomed by this zoom controller. @@ -118,34 +114,25 @@ public class ZoomButtonsController implements View.OnTouchListener { * The {@link #mTouchTargetView}'s location in window, set on touch down. */ private int[] mTouchTargetWindowLocation = new int[2]; + /** * If the zoom controller is dismissed but the user is still in a touch * interaction, we set this to true. This will ignore all touch events until * up/cancel, and then set the owner's touch listener to null. + *

+ * Otherwise, the owner view would get mismatched events (i.e., touch move + * even though it never got the touch down.) */ private boolean mReleaseTouchListenerOnUp; - /** - * Whether we are currently in the double-tap gesture, with the second tap - * still being performed (i.e., we're waiting for the second tap's touch up). - */ - private boolean mIsSecondTapDown; - /** Whether the container has been added to the window manager. */ private boolean mIsVisible; private Rect mTempRect = new Rect(); private int[] mTempIntArray = new int[2]; - + private OnZoomListener mCallback; - /** - * In 1.0, the ZoomControls were to be added to the UI by the client of - * WebView, MapView, etc. We didn't want apps to break, so we return a dummy - * view in place now. - */ - private InvisibleView mDummyZoomControls; - /** * When showing the zoom, we add the view as a new window. However, there is * logic that needs to know the size of the zoom which is determined after @@ -170,12 +157,6 @@ public class ZoomButtonsController implements View.OnTouchListener { } }; - /** - * The setting name that tracks whether we've shown the zoom tutorial. - */ - private static final String SETTING_NAME_SHOWN_TUTORIAL = "shown_zoom_tutorial"; - private static Dialog sTutorialDialog; - /** When configuration changes, this is called after the UI thread is idle. */ private static final int MSG_POST_CONFIGURATION_CHANGED = 2; /** Used to delay the zoom controller dismissal. */ @@ -215,7 +196,7 @@ public class ZoomButtonsController implements View.OnTouchListener { /** * Constructor for the {@link ZoomButtonsController}. - * + * * @param ownerView The view that is being zoomed by the zoom controls. The * zoom controls will be displayed aligned with this view. */ @@ -227,13 +208,13 @@ public class ZoomButtonsController implements View.OnTouchListener { mTouchPaddingScaledSq = (int) (ZOOM_CONTROLS_TOUCH_PADDING * mContext.getResources().getDisplayMetrics().density); mTouchPaddingScaledSq *= mTouchPaddingScaledSq; - + mContainer = createContainer(); } /** * Whether to enable the zoom in control. - * + * * @param enabled Whether to enable the zoom in control. */ public void setZoomInEnabled(boolean enabled) { @@ -242,7 +223,7 @@ public class ZoomButtonsController implements View.OnTouchListener { /** * Whether to enable the zoom out control. - * + * * @param enabled Whether to enable the zoom out control. */ public void setZoomOutEnabled(boolean enabled) { @@ -251,7 +232,7 @@ public class ZoomButtonsController implements View.OnTouchListener { /** * Sets the delay between zoom callbacks as the user holds a zoom button. - * + * * @param speed The delay in milliseconds between zoom callbacks. */ public void setZoomSpeed(long speed) { @@ -264,7 +245,8 @@ public class ZoomButtonsController implements View.OnTouchListener { lp.gravity = Gravity.TOP | Gravity.LEFT; lp.flags = LayoutParams.FLAG_NOT_TOUCHABLE | LayoutParams.FLAG_NOT_FOCUSABLE | - LayoutParams.FLAG_LAYOUT_NO_LIMITS; + LayoutParams.FLAG_LAYOUT_NO_LIMITS | + LayoutParams.FLAG_ALT_FOCUSABLE_IM; lp.height = LayoutParams.WRAP_CONTENT; lp.width = LayoutParams.FILL_PARENT; lp.type = LayoutParams.TYPE_APPLICATION_PANEL; @@ -299,7 +281,7 @@ public class ZoomButtonsController implements View.OnTouchListener { /** * Sets the {@link OnZoomListener} listener that receives callbacks to zoom. - * + * * @param listener The listener that will be told to zoom. */ public void setOnZoomListener(OnZoomListener listener) { @@ -310,7 +292,7 @@ public class ZoomButtonsController implements View.OnTouchListener { * Sets whether the zoom controls should be focusable. If the controls are * focusable, then trackball and arrow key interactions are possible. * Otherwise, only touch interactions are possible. - * + * * @param focusable Whether the zoom controls should be focusable. */ public void setFocusable(boolean focusable) { @@ -326,9 +308,27 @@ public class ZoomButtonsController implements View.OnTouchListener { } } + /** + * Whether the zoom controls will be automatically dismissed after showing. + * + * @return Whether the zoom controls will be auto dismissed after showing. + */ + public boolean isAutoDismissed() { + return mAutoDismissControls; + } + + /** + * Sets whether the zoom controls will be automatically dismissed after + * showing. + */ + public void setAutoDismissed(boolean autoDismiss) { + if (mAutoDismissControls == autoDismiss) return; + mAutoDismissControls = autoDismiss; + } + /** * Whether the zoom controls are visible to the user. - * + * * @return Whether the zoom controls are visible to the user. */ public boolean isVisible() { @@ -337,7 +337,7 @@ public class ZoomButtonsController implements View.OnTouchListener { /** * Sets whether the zoom controls should be visible to the user. - * + * * @param visible Whether the zoom controls should be visible to the user. */ public void setVisible(boolean visible) { @@ -419,7 +419,7 @@ public class ZoomButtonsController implements View.OnTouchListener { *

* The client can add other views to this container to link them with the * zoom controls. - * + * * @return The container of the zoom controls. It will be a layout that * respects the gravity of a child's layout parameters. */ @@ -427,43 +427,20 @@ public class ZoomButtonsController implements View.OnTouchListener { return mContainer; } - private void dismissControlsDelayed(int delay) { - mHandler.removeMessages(MSG_DISMISS_ZOOM_CONTROLS); - mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_CONTROLS, delay); + /** + * Gets the view for the zoom controls. + * + * @return The zoom controls view. + */ + public View getZoomControls() { + return mControls; } - /** - * Should be called by the client for each event belonging to the second tap - * (the down, move, up, and/or cancel events). - * - * @param event The event belonging to the second tap. - * @return Whether the event was consumed. - */ - public boolean handleDoubleTapEvent(MotionEvent event) { - int action = event.getAction(); - - if (action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - /* - * This class will consume all events in the second tap (down, - * move(s), up). But, the owner already got the second tap's down, - * so cancel that. Do this before setVisible, since that call - * will set us as a touch listener. - */ - MotionEvent cancelEvent = MotionEvent.obtain(event.getDownTime(), - SystemClock.elapsedRealtime(), - MotionEvent.ACTION_CANCEL, 0, 0, 0); - mOwnerView.dispatchTouchEvent(cancelEvent); - cancelEvent.recycle(); - - setVisible(true); - centerPoint(x, y); - mIsSecondTapDown = true; + private void dismissControlsDelayed(int delay) { + if (mAutoDismissControls) { + mHandler.removeMessages(MSG_DISMISS_ZOOM_CONTROLS); + mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_CONTROLS, delay); } - - return true; } private void refreshPositioningVariables() { @@ -477,7 +454,7 @@ public class ZoomButtonsController implements View.OnTouchListener { mOwnerView.getLocationOnScreen(mOwnerViewRawLocation); mContainerRawLocation[0] = mOwnerViewRawLocation[0]; mContainerRawLocation[1] = mOwnerViewRawLocation[1] + containerOwnerYOffset; - + int[] ownerViewWindowLoc = mTempIntArray; mOwnerView.getLocationInWindow(ownerViewWindowLoc); @@ -488,39 +465,30 @@ public class ZoomButtonsController implements View.OnTouchListener { if (mIsVisible) { mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams); } - - } - /** - * Centers the point (in owner view's coordinates). - */ - private void centerPoint(int x, int y) { - if (mCallback != null) { - mCallback.onCenter(x, y); - } } /* This will only be called when the container has focus. */ private boolean onContainerKey(KeyEvent event) { int keyCode = event.getKeyCode(); if (isInterestingKey(keyCode)) { - + if (keyCode == KeyEvent.KEYCODE_BACK) { setVisible(false); } else { dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT); } - + // Let the container handle the key return false; - + } else { - + ViewRoot viewRoot = getOwnerViewRoot(); if (viewRoot != null) { viewRoot.dispatchKey(event); } - + // We gave the key to the owner, don't let the container handle this key return true; } @@ -540,13 +508,13 @@ public class ZoomButtonsController implements View.OnTouchListener { return false; } } - + private ViewRoot getOwnerViewRoot() { View rootViewOfOwner = mOwnerView.getRootView(); if (rootViewOfOwner == null) { return null; } - + ViewParent parentOfRootView = rootViewOfOwner.getParent(); if (parentOfRootView instanceof ViewRoot) { return (ViewRoot) parentOfRootView; @@ -562,13 +530,6 @@ public class ZoomButtonsController implements View.OnTouchListener { public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); - // Consume all events during the second-tap interaction (down, move, up/cancel) - boolean consumeEvent = mIsSecondTapDown; - if ((action == MotionEvent.ACTION_UP) || (action == MotionEvent.ACTION_CANCEL)) { - // The second tap can no longer be down - mIsSecondTapDown = false; - } - if (mReleaseTouchListenerOnUp) { // The controls were dismissed but we need to throw away all events until the up if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { @@ -609,18 +570,21 @@ public class ZoomButtonsController implements View.OnTouchListener { mOwnerViewRawLocation[1] - targetViewRawY); /* Disallow negative coordinates (which can occur due to * ZOOM_CONTROLS_TOUCH_PADDING) */ - if (containerEvent.getX() < 0) { - containerEvent.offsetLocation(-containerEvent.getX(), 0); + // These are floats because we need to potentially offset away this exact amount + float containerX = containerEvent.getX(); + float containerY = containerEvent.getY(); + if (containerX < 0 && containerX > -ZOOM_CONTROLS_TOUCH_PADDING) { + containerEvent.offsetLocation(-containerX, 0); } - if (containerEvent.getY() < 0) { - containerEvent.offsetLocation(0, -containerEvent.getY()); + if (containerY < 0 && containerY > -ZOOM_CONTROLS_TOUCH_PADDING) { + containerEvent.offsetLocation(0, -containerY); } boolean retValue = targetView.dispatchTouchEvent(containerEvent); containerEvent.recycle(); - return retValue || consumeEvent; + return retValue; } else { - return consumeEvent; + return false; } } @@ -646,7 +610,7 @@ public class ZoomButtonsController implements View.OnTouchListener { View closestChild = null; int closestChildDistanceSq = Integer.MAX_VALUE; - + for (int i = mContainer.getChildCount() - 1; i >= 0; i--) { View child = mContainer.getChildAt(i); if (child.getVisibility() != View.VISIBLE) { @@ -657,13 +621,23 @@ public class ZoomButtonsController implements View.OnTouchListener { if (frame.contains(containerCoordsX, containerCoordsY)) { return child; } - - int distanceX = Math.min(Math.abs(frame.left - containerCoordsX), + + int distanceX; + if (containerCoordsX >= frame.left && containerCoordsX <= frame.right) { + distanceX = 0; + } else { + distanceX = Math.min(Math.abs(frame.left - containerCoordsX), Math.abs(containerCoordsX - frame.right)); - int distanceY = Math.min(Math.abs(frame.top - containerCoordsY), - Math.abs(containerCoordsY - frame.bottom)); + } + int distanceY; + if (containerCoordsY >= frame.top && containerCoordsY <= frame.bottom) { + distanceY = 0; + } else { + distanceY = Math.min(Math.abs(frame.top - containerCoordsY), + Math.abs(containerCoordsY - frame.bottom)); + } int distanceSq = distanceX * distanceX + distanceY * distanceY; - + if ((distanceSq < mTouchPaddingScaledSq) && (distanceSq < closestChildDistanceSq)) { closestChild = child; @@ -679,130 +653,27 @@ public class ZoomButtonsController implements View.OnTouchListener { refreshPositioningVariables(); } - /* - * This is static so Activities can call this instead of the Views - * (Activities usually do not have a reference to the ZoomButtonsController - * instance.) - */ - /** - * Shows a "tutorial" (some text) to the user teaching her the new zoom - * invocation method. Must call from the main thread. - *

- * It checks the global system setting to ensure this has not been seen - * before. Furthermore, if the application does not have privilege to write - * to the system settings, it will store this bit locally in a shared - * preference. - * - * @hide This should only be used by our main apps--browser, maps, and - * gallery - */ - public static void showZoomTutorialOnce(Context context) { - - // TODO: remove this code, but to hit the weekend build, just never show - if (true) return; - - ContentResolver cr = context.getContentResolver(); - if (Settings.System.getInt(cr, SETTING_NAME_SHOWN_TUTORIAL, 0) == 1) { - return; - } - - SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE); - if (sp.getInt(SETTING_NAME_SHOWN_TUTORIAL, 0) == 1) { - return; - } - - if (sTutorialDialog != null && sTutorialDialog.isShowing()) { - sTutorialDialog.dismiss(); - } - - LayoutInflater layoutInflater = - (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - TextView textView = (TextView) layoutInflater.inflate( - com.android.internal.R.layout.alert_dialog_simple_text, null) - .findViewById(android.R.id.text1); - textView.setText(com.android.internal.R.string.tutorial_double_tap_to_zoom_message_short); - - sTutorialDialog = new AlertDialog.Builder(context) - .setView(textView) - .setIcon(0) - .create(); - - Window window = sTutorialDialog.getWindow(); - window.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); - window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND | - WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); - - sTutorialDialog.show(); - } - - /** @hide Should only be used by Android platform apps */ - public static void finishZoomTutorial(Context context, boolean userNotified) { - if (sTutorialDialog == null) return; - - sTutorialDialog.dismiss(); - sTutorialDialog = null; - - // Record that they have seen the tutorial - if (userNotified) { - try { - Settings.System.putInt(context.getContentResolver(), SETTING_NAME_SHOWN_TUTORIAL, - 1); - } catch (SecurityException e) { - /* - * The app does not have permission to clear this global flag, make - * sure the user does not see the message when he comes back to this - * same app at least. - */ - SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE); - sp.edit().putInt(SETTING_NAME_SHOWN_TUTORIAL, 1).commit(); - } - } - } - - /** @hide Should only be used by Android platform apps */ - public void finishZoomTutorial() { - finishZoomTutorial(mContext, true); - } - - /** @hide Should only be used only be WebView and MapView */ - public View getDummyZoomControls() { - if (mDummyZoomControls == null) { - mDummyZoomControls = new InvisibleView(mContext); - } - return mDummyZoomControls; - } - /** * Interface that will be called when the user performs an interaction that * triggers some action, for example zooming. */ public interface OnZoomListener { - /** - * Called when the given point should be centered. The point will be in - * owner view coordinates. - * - * @param x The x of the point. - * @param y The y of the point. - */ - void onCenter(int x, int y); - + /** * Called when the zoom controls' visibility changes. - * + * * @param visible Whether the zoom controls are visible. */ void onVisibilityChanged(boolean visible); - + /** * Called when the owner view needs to be zoomed. - * + * * @param zoomIn The direction of the zoom: true to zoom in, false to zoom out. */ void onZoom(boolean zoomIn); } - + private class Container extends FrameLayout { public Container(Context context) { super(context); @@ -820,29 +691,4 @@ public class ZoomButtonsController implements View.OnTouchListener { } } - /** - * An InvisibleView is an invisible, zero-sized View for backwards - * compatibility - */ - private final class InvisibleView extends View { - - private InvisibleView(Context context) { - super(context); - setVisibility(GONE); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(0, 0); - } - - @Override - public void draw(Canvas canvas) { - } - - @Override - protected void dispatchDraw(Canvas canvas) { - } - } - } diff --git a/core/java/android/widget/ZoomControls.java b/core/java/android/widget/ZoomControls.java index 84d8f0e015b39..a12aee5d4bb3a 100644 --- a/core/java/android/widget/ZoomControls.java +++ b/core/java/android/widget/ZoomControls.java @@ -30,11 +30,6 @@ import com.android.internal.R; /** * The {@code ZoomControls} class displays a simple set of controls used for zooming and * provides callbacks to register for events. */ -// TODO: pending API council -// *

-// * Instead of using this directly, consider using the {@link ZoomButtonsController} which -// * handles displaying the zoom controls. -// */ @Widget public class ZoomControls extends LinearLayout { diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 5c44b2df661d5..b330a1862174c 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -361,11 +361,14 @@ public class AlertController { if (mView != null) { customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel); FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom); - custom.addView(mView, new LayoutParams(FILL_PARENT, WRAP_CONTENT)); + custom.addView(mView, new LayoutParams(FILL_PARENT, FILL_PARENT)); if (mViewSpacingSpecified) { custom.setPadding(mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom); } + if (mListView != null) { + ((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0; + } } else { mWindow.findViewById(R.id.customPanel).setVisibility(View.GONE); } @@ -456,7 +459,9 @@ public class AlertController { if (mListView != null) { contentPanel.removeView(mWindow.findViewById(R.id.scrollView)); - contentPanel.addView(mListView, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT)); + contentPanel.addView(mListView, + new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT)); + contentPanel.setLayoutParams(new LinearLayout.LayoutParams(FILL_PARENT, 0, 1.0f)); } else { contentPanel.setVisibility(View.GONE); } diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index edda1d9230059..d259756530654 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -30,7 +30,15 @@ interface IBatteryStats { void noteScreenOff(); void notePhoneOn(); void notePhoneOff(); - void setOnBattery(boolean onBattery); + void noteWifiOn(); + void noteWifiOff(); + void noteBluetoothOn(); + void noteBluetoothOff(); + void noteFullWifiLockAcquired(int uid); + void noteFullWifiLockReleased(int uid); + void noteScanWifiLockAcquired(int uid); + void noteScanWifiLockReleased(int uid); + void setOnBattery(boolean onBattery, int level); long getAwakeTimeBattery(); long getAwakeTimePlugged(); } diff --git a/core/java/com/android/internal/app/RingtonePickerActivity.java b/core/java/com/android/internal/app/RingtonePickerActivity.java index 1f8e6f02f9817..5a0fea383d846 100644 --- a/core/java/com/android/internal/app/RingtonePickerActivity.java +++ b/core/java/com/android/internal/app/RingtonePickerActivity.java @@ -247,9 +247,13 @@ public final class RingtonePickerActivity extends AlertActivity implements } else { setResult(RESULT_CANCELED); } - - mCursor.deactivate(); - + + getWindow().getDecorView().post(new Runnable() { + public void run() { + mCursor.deactivate(); + } + }); + finish(); } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 7eea8b73da0d4..b3ae0d6adaa75 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -47,7 +47,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 25; + private static final int VERSION = 27; private final File mFile; private final File mBackupFile; @@ -92,6 +92,12 @@ public final class BatteryStatsImpl extends BatteryStats { boolean mPhoneOn; Timer mPhoneOnTimer; + boolean mWifiOn; + Timer mWifiOnTimer; + + boolean mBluetoothOn; + Timer mBluetoothOnTimer; + /** * These provide time bases that discount the time the device is plugged * in to power. @@ -106,6 +112,12 @@ public final class BatteryStatsImpl extends BatteryStats { long mUnpluggedBatteryUptime; long mUnpluggedBatteryRealtime; + /* + * These keep track of battery levels (1-100) at the last plug event and the last unplug event. + */ + int mUnpluggedStartLevel; + int mPluggedStartLevel; + long mLastWriteTime = 0; // Milliseconds // For debugging @@ -471,6 +483,62 @@ public final class BatteryStatsImpl extends BatteryStats { } } + public void noteWifiOnLocked() { + if (!mWifiOn) { + mWifiOn = true; + mWifiOnTimer.startRunningLocked(this); + } + } + + public void noteWifiOffLocked() { + if (mWifiOn) { + mWifiOn = false; + mWifiOnTimer.stopRunningLocked(this); + } + } + + public void noteBluetoothOnLocked() { + if (!mBluetoothOn) { + mBluetoothOn = true; + mBluetoothOnTimer.startRunningLocked(this); + } + } + + public void noteBluetoothOffLocked() { + if (mBluetoothOn) { + mBluetoothOn = false; + mBluetoothOnTimer.stopRunningLocked(this); + } + } + + public void noteFullWifiLockAcquiredLocked(int uid) { + Uid u = mUidStats.get(uid); + if (u != null) { + u.noteFullWifiLockAcquiredLocked(); + } + } + + public void noteFullWifiLockReleasedLocked(int uid) { + Uid u = mUidStats.get(uid); + if (u != null) { + u.noteFullWifiLockReleasedLocked(); + } + } + + public void noteScanWifiLockAcquiredLocked(int uid) { + Uid u = mUidStats.get(uid); + if (u != null) { + u.noteScanWifiLockAcquiredLocked(); + } + } + + public void noteScanWifiLockReleasedLocked(int uid) { + Uid u = mUidStats.get(uid); + if (u != null) { + u.noteScanWifiLockReleasedLocked(); + } + } + @Override public long getScreenOnTime(long batteryRealtime, int which) { return mScreenOnTimer.getTotalTime(batteryRealtime, which); } @@ -479,6 +547,14 @@ public final class BatteryStatsImpl extends BatteryStats { return mPhoneOnTimer.getTotalTime(batteryRealtime, which); } + @Override public long getWifiOnTime(long batteryRealtime, int which) { + return mWifiOnTimer.getTotalTime(batteryRealtime, which); + } + + @Override public long getBluetoothOnTime(long batteryRealtime, int which) { + return mBluetoothOnTimer.getTotalTime(batteryRealtime, which); + } + @Override public boolean getIsOnBattery() { return mOnBattery; } @@ -505,6 +581,12 @@ public final class BatteryStatsImpl extends BatteryStats { long mStartedTcpBytesReceived = -1; long mStartedTcpBytesSent = -1; + boolean mFullWifiLockOut; + Timer mFullWifiLockTimer; + + boolean mScanWifiLockOut; + Timer mScanWifiLockTimer; + /** * The statistics we have collected for this uid's wake locks. */ @@ -527,6 +609,8 @@ public final class BatteryStatsImpl extends BatteryStats { public Uid(int uid) { mUid = uid; + mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables); + mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables); } @Override @@ -586,6 +670,47 @@ public final class BatteryStatsImpl extends BatteryStats { } } + @Override + public void noteFullWifiLockAcquiredLocked() { + if (!mFullWifiLockOut) { + mFullWifiLockOut = true; + mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this); + } + } + + @Override + public void noteFullWifiLockReleasedLocked() { + if (mFullWifiLockOut) { + mFullWifiLockOut = false; + mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this); + } + } + + @Override + public void noteScanWifiLockAcquiredLocked() { + if (!mScanWifiLockOut) { + mScanWifiLockOut = true; + mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this); + } + } + + @Override + public void noteScanWifiLockReleasedLocked() { + if (mScanWifiLockOut) { + mScanWifiLockOut = false; + mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this); + } + } + @Override + public long getFullWifiLockTime(long batteryRealtime, int which) { + return mFullWifiLockTimer.getTotalTime(batteryRealtime, which); + } + + @Override + public long getScanWifiLockTime(long batteryRealtime, int which) { + return mScanWifiLockTimer.getTotalTime(batteryRealtime, which); + } + public long computeCurrentTcpBytesSent() { return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0 ? (NetStat.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0); @@ -626,6 +751,8 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(computeCurrentTcpBytesSent()); out.writeLong(mTcpBytesReceivedAtLastUnplug); out.writeLong(mTcpBytesSentAtLastUnplug); + mFullWifiLockTimer.writeToParcel(out, batteryRealtime); + mScanWifiLockTimer.writeToParcel(out, batteryRealtime); } void readFromParcelLocked(ArrayList unpluggables, Parcel in) { @@ -671,6 +798,10 @@ public final class BatteryStatsImpl extends BatteryStats { mCurrentTcpBytesSent = in.readLong(); mTcpBytesReceivedAtLastUnplug = in.readLong(); mTcpBytesSentAtLastUnplug = in.readLong(); + mFullWifiLockOut = false; + mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables, in); + mScanWifiLockOut = false; + mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables, in); } /** @@ -852,6 +983,9 @@ public final class BatteryStatsImpl extends BatteryStats { } void writeToParcelLocked(Parcel out) { + final long uSecRealtime = SystemClock.elapsedRealtime() * 1000; + final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime); + out.writeLong(mUserTime); out.writeLong(mSystemTime); out.writeInt(mStarts); @@ -1462,6 +1596,8 @@ public final class BatteryStatsImpl extends BatteryStats { mStartCount++; mScreenOnTimer = new Timer(-1, null, mUnpluggables); mPhoneOnTimer = new Timer(-2, null, mUnpluggables); + mWifiOnTimer = new Timer(-3, null, mUnpluggables); + mBluetoothOnTimer = new Timer(-4, null, mUnpluggables); mOnBattery = mOnBatteryInternal = false; mTrackBatteryPastUptime = 0; mTrackBatteryPastRealtime = 0; @@ -1469,6 +1605,8 @@ public final class BatteryStatsImpl extends BatteryStats { mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000; mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart); mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart); + mUnpluggedStartLevel = 0; + mPluggedStartLevel = 0; } public BatteryStatsImpl(Parcel p) { @@ -1485,7 +1623,7 @@ public final class BatteryStatsImpl extends BatteryStats { return mOnBattery; } - public void setOnBattery(boolean onBattery) { + public void setOnBattery(boolean onBattery, int level) { synchronized(this) { if (mOnBattery != onBattery) { mOnBattery = mOnBatteryInternal = onBattery; @@ -1498,10 +1636,12 @@ public final class BatteryStatsImpl extends BatteryStats { mTrackBatteryRealtimeStart = realtime; mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime); mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime); + mUnpluggedStartLevel = level; doUnplug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime); } else { mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart; mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart; + mPluggedStartLevel = level; doPlug(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime)); } if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) { @@ -1602,6 +1742,28 @@ public final class BatteryStatsImpl extends BatteryStats { public long getBatteryRealtime(long curTime) { return getBatteryRealtimeLocked(curTime); } + + @Override + public int getUnpluggedStartLevel() { + synchronized(this) { + return getUnluggedStartLevelLocked(); + } + } + + public int getUnluggedStartLevelLocked() { + return mUnpluggedStartLevel; + } + + @Override + public int getPluggedStartLevel() { + synchronized(this) { + return getPluggedStartLevelLocked(); + } + } + + public int getPluggedStartLevelLocked() { + return mPluggedStartLevel; + } /** * Retrieve the statistics object for a particular uid, creating if needed. @@ -1762,12 +1924,19 @@ public final class BatteryStatsImpl extends BatteryStats { mLastUptime = in.readLong(); mRealtime = in.readLong(); mLastRealtime = in.readLong(); + mUnpluggedStartLevel = in.readInt(); + mPluggedStartLevel = in.readInt(); + mStartCount++; mScreenOn = false; mScreenOnTimer.readSummaryFromParcelLocked(in); mPhoneOn = false; mPhoneOnTimer.readSummaryFromParcelLocked(in); + mWifiOn = false; + mWifiOnTimer.readSummaryFromParcelLocked(in); + mBluetoothOn = false; + mBluetoothOnTimer.readSummaryFromParcelLocked(in); final int NU = in.readInt(); for (int iu = 0; iu < NU; iu++) { @@ -1775,6 +1944,11 @@ public final class BatteryStatsImpl extends BatteryStats { Uid u = new Uid(uid); mUidStats.put(uid, u); + u.mFullWifiLockOut = false; + u.mFullWifiLockTimer.readSummaryFromParcelLocked(in); + u.mScanWifiLockOut = false; + u.mScanWifiLockTimer.readSummaryFromParcelLocked(in); + int NW = in.readInt(); for (int iw = 0; iw < NW; iw++) { String wlName = in.readString(); @@ -1857,15 +2031,23 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT)); out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL)); out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT)); + out.writeInt(mUnpluggedStartLevel); + out.writeInt(mPluggedStartLevel); + mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); + mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); + mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { out.writeInt(mUidStats.keyAt(iu)); Uid u = mUidStats.valueAt(iu); + + u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL); + u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL); int NW = u.mWakelockStats.size(); out.writeInt(NW); @@ -1979,6 +2161,10 @@ public final class BatteryStatsImpl extends BatteryStats { mScreenOnTimer = new Timer(-1, null, mUnpluggables, in); mPhoneOn = false; mPhoneOnTimer = new Timer(-2, null, mUnpluggables, in); + mWifiOn = false; + mWifiOnTimer = new Timer(-2, null, mUnpluggables, in); + mBluetoothOn = false; + mBluetoothOnTimer = new Timer(-2, null, mUnpluggables, in); mUptime = in.readLong(); mUptimeStart = in.readLong(); mLastUptime = in.readLong(); @@ -1993,6 +2179,8 @@ public final class BatteryStatsImpl extends BatteryStats { mTrackBatteryRealtimeStart = in.readLong(); mUnpluggedBatteryUptime = in.readLong(); mUnpluggedBatteryRealtime = in.readLong(); + mUnpluggedStartLevel = in.readInt(); + mPluggedStartLevel = in.readInt(); mLastWriteTime = in.readLong(); mPartialTimers.clear(); @@ -2028,6 +2216,8 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(mBatteryLastRealtime); mScreenOnTimer.writeToParcel(out, batteryRealtime); mPhoneOnTimer.writeToParcel(out, batteryRealtime); + mWifiOnTimer.writeToParcel(out, batteryRealtime); + mBluetoothOnTimer.writeToParcel(out, batteryRealtime); out.writeLong(mUptime); out.writeLong(mUptimeStart); out.writeLong(mLastUptime); @@ -2041,6 +2231,8 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(mTrackBatteryRealtimeStart); out.writeLong(mUnpluggedBatteryUptime); out.writeLong(mUnpluggedBatteryRealtime); + out.writeInt(mUnpluggedStartLevel); + out.writeInt(mPluggedStartLevel); out.writeLong(mLastWriteTime); int size = mUidStats.size(); @@ -2070,6 +2262,10 @@ public final class BatteryStatsImpl extends BatteryStats { mScreenOnTimer.logState(); Log.i(TAG, "*** Phone timer:"); mPhoneOnTimer.logState(); + Log.i(TAG, "*** Wifi timer:"); + mWifiOnTimer.logState(); + Log.i(TAG, "*** Bluetooth timer:"); + mBluetoothOnTimer.logState(); } super.dumpLocked(pw); } diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java index 9e1f2aedca475..66e15c1c28b97 100644 --- a/core/java/com/android/internal/view/menu/IconMenuItemView.java +++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java @@ -28,6 +28,7 @@ import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewDebug; import android.widget.TextView; +import android.text.Layout; /** * The item view for each item in the {@link IconMenuView}. @@ -236,6 +237,32 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie positionIcon(); } + @Override + protected void onTextChanged(CharSequence text, int start, int before, int after) { + super.onTextChanged(text, start, before, after); + + // our layout params depend on the length of the text + setLayoutParams(getTextAppropriateLayoutParams()); + } + + /** + * @return layout params appropriate for this view. If layout params already exist, it will + * augment them to be appropriate to the current text size. + */ + IconMenuView.LayoutParams getTextAppropriateLayoutParams() { + IconMenuView.LayoutParams lp = (IconMenuView.LayoutParams) getLayoutParams(); + if (lp == null) { + // Default layout parameters + lp = new IconMenuView.LayoutParams( + IconMenuView.LayoutParams.FILL_PARENT, IconMenuView.LayoutParams.FILL_PARENT); + } + + // Set the desired width of item + lp.desiredWidth = (int) Layout.getDesiredWidth(getText(), getPaint()); + + return lp; + } + /** * Positions the icon vertically (horizontal centering is taken care of by * the TextView's gravity). @@ -280,5 +307,5 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie public boolean showsIcon() { return true; } - + } diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java index 781c608aaebb7..6034a1e6e82d2 100644 --- a/core/java/com/android/internal/view/menu/IconMenuView.java +++ b/core/java/com/android/internal/view/menu/IconMenuView.java @@ -26,7 +26,6 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; -import android.text.Layout; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; @@ -278,14 +277,7 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi * Adds an IconMenuItemView to this icon menu view. * @param itemView The item's view to add */ - private void addItemView(IconMenuItemView itemView) { - LayoutParams lp = (LayoutParams) itemView.getLayoutParams(); - - if (lp == null) { - // Default layout parameters - lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); - } - + private void addItemView(IconMenuItemView itemView) { // Set ourselves on the item view itemView.setIconMenuView(this); @@ -295,10 +287,7 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi // This class is the invoker for all its item views itemView.setItemInvoker(this); - // Set the desired width of item - lp.desiredWidth = (int) Layout.getDesiredWidth(itemView.getText(), itemView.getPaint()); - - addView(itemView, lp); + addView(itemView, itemView.getTextAppropriateLayoutParams()); } /** diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp index dee3fdd97f691..f0b35e977ef1c 100644 --- a/core/jni/android_location_GpsLocationProvider.cpp +++ b/core/jni/android_location_GpsLocationProvider.cpp @@ -35,6 +35,7 @@ static jmethodID method_xtraDownloadRequest; static const GpsInterface* sGpsInterface = NULL; static const GpsXtraInterface* sGpsXtraInterface = NULL; +static const GpsSuplInterface* sGpsSuplInterface = NULL; // data written to by GPS callbacks static GpsLocation sGpsLocation; @@ -144,9 +145,10 @@ static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject ob sGpsInterface->cleanup(); } -static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jboolean singleFix, jint fixFrequency) +static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode, + jboolean singleFix, jint fixFrequency) { - int result = sGpsInterface->set_position_mode(GPS_POSITION_MODE_STANDALONE, (singleFix ? 0 : fixFrequency)); + int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency)); if (result) { return result; } @@ -267,6 +269,33 @@ static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, j env->ReleaseByteArrayElements(data, bytes, 0); } +static void android_location_GpsLocationProvider_set_supl_server(JNIEnv* env, jobject obj, + jint addr, jint port) +{ + if (!sGpsSuplInterface) { + sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE); + } + if (sGpsSuplInterface) { + sGpsSuplInterface->set_server(addr, port); + } +} + +static void android_location_GpsLocationProvider_set_supl_apn(JNIEnv* env, jobject obj, jstring apn) +{ + if (!sGpsSuplInterface) { + sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE); + } + if (sGpsSuplInterface) { + if (apn == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + const char *apnStr = env->GetStringUTFChars(apn, NULL); + sGpsSuplInterface->set_apn(apnStr); + env->ReleaseStringUTFChars(apn, apnStr); + } +} + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, @@ -274,7 +303,7 @@ static JNINativeMethod sMethods[] = { {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init}, {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable}, {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup}, - {"native_start", "(ZI)Z", (void*)android_location_GpsLocationProvider_start}, + {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start}, {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop}, {"native_set_fix_frequency", "(I)V", (void*)android_location_GpsLocationProvider_set_fix_frequency}, {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data}, @@ -283,6 +312,8 @@ static JNINativeMethod sMethods[] = { {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time}, {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra}, {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data}, + {"native_set_supl_server", "(II)V", (void*)android_location_GpsLocationProvider_set_supl_server}, + {"native_set_supl_apn", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_set_supl_apn}, }; int register_android_location_GpsLocationProvider(JNIEnv* env) diff --git a/core/jni/android_os_Hardware.cpp b/core/jni/android_os_Hardware.cpp index bc8af7801707a..8007662a9fe1a 100644 --- a/core/jni/android_os_Hardware.cpp +++ b/core/jni/android_os_Hardware.cpp @@ -15,7 +15,6 @@ */ #include -#include #include #include @@ -24,12 +23,6 @@ namespace android { -static jboolean -setLedState(JNIEnv *env, jobject clazz, jint colorARGB, jint onMS, jint offMS) -{ - return set_led_state(colorARGB, onMS, offMS); -} - static jint getFlashlightEnabled(JNIEnv *env, jobject clazz) { @@ -48,24 +41,6 @@ enableCameraFlash(JNIEnv *env, jobject clazz, jint milliseconds) enable_camera_flash(milliseconds); } -static void -setScreenBacklight(JNIEnv *env, jobject clazz, jint brightness) -{ - set_light_brightness(SCREEN_LIGHT, brightness); -} - -static void -setKeyboardBacklight(JNIEnv *env, jobject clazz, jboolean on) -{ - set_light_brightness(KEYBOARD_LIGHT, (on ? 255 : 0)); -} - -static void -setButtonBacklight(JNIEnv *env, jobject clazz, jboolean on) -{ - set_light_brightness(BUTTON_LIGHT, (on ? 255 : 0)); -} - // ============================================================================ /* * JNI registration. @@ -73,13 +48,9 @@ setButtonBacklight(JNIEnv *env, jobject clazz, jboolean on) static JNINativeMethod g_methods[] = { /* name, signature, funcPtr */ - { "setLedState", "(III)I", (void*)setLedState }, { "getFlashlightEnabled", "()Z", (void*)getFlashlightEnabled }, { "setFlashlightEnabled", "(Z)V", (void*)setFlashlightEnabled }, { "enableCameraFlash", "(I)V", (void*)enableCameraFlash }, - { "setScreenBacklight", "(I)V", (void*)setScreenBacklight }, - { "setKeyboardBacklight", "(Z)V", (void*)setKeyboardBacklight }, - { "setButtonBacklight", "(Z)V", (void*)setButtonBacklight }, }; int register_android_os_Hardware(JNIEnv* env) diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp index c2d75b1fe3e69..df5edba4eb766 100644 --- a/core/jni/android_os_Power.cpp +++ b/core/jni/android_os_Power.cpp @@ -69,12 +69,6 @@ setLastUserActivityTimeout(JNIEnv *env, jobject clazz, jlong timeMS) return set_last_user_activity_timeout(timeMS/1000); } -static int -setLightBrightness(JNIEnv *env, jobject clazz, jint mask, jint brightness) -{ - return set_light_brightness(mask, brightness); -} - static int setScreenState(JNIEnv *env, jobject clazz, jboolean on) { @@ -109,7 +103,6 @@ static JNINativeMethod method_table[] = { { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock }, { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock }, { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout }, - { "setLightBrightness", "(II)I", (void*)setLightBrightness }, { "setScreenState", "(Z)I", (void*)setScreenState }, { "shutdown", "()V", (void*)android_os_Power_shutdown }, { "reboot", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot }, diff --git a/core/res/assets/webkit/youtube.html b/core/res/assets/webkit/youtube.html index 5a40c1e71f08b..2aaaa15b29ada 100644 --- a/core/res/assets/webkit/youtube.html +++ b/core/res/assets/webkit/youtube.html @@ -43,7 +43,7 @@ diff --git a/core/res/res/anim/input_method_extract_enter.xml b/core/res/res/anim/input_method_extract_enter.xml new file mode 100644 index 0000000000000..96b049f361778 --- /dev/null +++ b/core/res/res/anim/input_method_extract_enter.xml @@ -0,0 +1,24 @@ + + + + diff --git a/core/res/res/anim/input_method_extract_exit.xml b/core/res/res/anim/input_method_extract_exit.xml new file mode 100644 index 0000000000000..26db13f48dedb --- /dev/null +++ b/core/res/res/anim/input_method_extract_exit.xml @@ -0,0 +1,25 @@ + + + + diff --git a/core/res/res/drawable-land/statusbar_background.png b/core/res/res/drawable-land/statusbar_background.png index 2a351a5f96e6b54457adb6c9e4f6ea2a6f459ae8..ef61e5273cf362b8b1879e10c64caea0a3758662 100644 GIT binary patch delta 4444 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 i7)D|JB3}KU00RKWZ?l4 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 QNuWUtp00i_>zopr0D!wCg8%>k delta 121 zcmZo>>|j*v4DfU3<&xrJU|`_&^l%9R((FLY&A|pFH&2+pVxppizm=zpV~E7mv*)#i z7!-J%4_@y-s9<6A{hbK&y01r4&C~+a8UKi}vl%ps3f?{wbbnP>*#}*(cK%iCix{;1 W*$+n@d;T408iS{+pUXO@geCyc7bcnj diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.xml b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.xml new file mode 100644 index 0000000000000..2db3203200d2c --- /dev/null +++ b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_disabled.png b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..859900a89bfd043911411c5ef9c1b06864bd5401 GIT binary patch literal 461 zcmeAS@N?(olHy`uVBq!ia0vp^YCvqj!3HF2H*shHDajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_cg42=1nE{-7;x86)U=y%wFr%hNR>5`gn5>u}0hTC~_EZ_aC zWbKnFbCedAS&+2!w{A?z8kV&erpU>h^m=;Zq`LZF;rP(0uam8dY;)Pt5+KMn^X9_F zd%vSgm>*WPi*8`IVUY`cW4SB)hUOa=p1q3S)`c2uNxw1q)7p&}qS%Er9@u@b40Jvo zoAXqSMfE{O&S&}boW4~t|2BLzF?-LnX3h5g-{Ln+SdQ=0Jbq%1QRvZE#!DX-F;30a znELpZ-Jf{&xm64nc6V3|gbEikOgUre!}{;jv*S)IW(Q@ypW5H?cjMfKn^V7Zuiew6 z%luEZx0I=^HI318M?>z%TID}q_AWKlRjumVrZw$4x8~fc*0nBox@zy2^!>JJjS<;1 zq5H*@Zja70nn9ZOp-D2$LEo2%JT!bhO;gJ)_xcl|@AH>h30Izs7msZAw(-^#U%E;r z_u_=B_9e|6H_V+Po~-c71epVIEGZ*dUMN=>wp3eYk+d>-v5ra4W_#9VzV^&@E6uj zc({8>pP|>eGZod-M1Ov{r(fzGl^v*@Bt64({WN~2)_)Rnp9)<29oAQ5zVWNm!T{5Z zy#X2_%8m;IR!Fq~`MoTyP7As2S1k-2X!4n$p7Ue3VG;Jv}O!qeI9 Q6woCMp00i_>zopr0F#kXLI3~& diff --git a/core/res/res/drawable/status_bar_background.png b/core/res/res/drawable/status_bar_background.png new file mode 100644 index 0000000000000000000000000000000000000000..cd111664d3044dcddd2fa6e3155dd595620e3b5d GIT binary patch literal 3109 zcmcgv^;Z=768|Ddmq;TD(kq?PuuFF=vV_tsh@>bbNQZDqX%<1HLnIcLP`X)4atY}Y zyq6G^*oXI=_sjbO-Z?Y#nK@Hu=BJrBBLht;a#nHx0F}0un#mRV|6$T=R}xKJ7vWq$J5#MiPKf~9Lf|4H{E7b zJXt(~>c)n?*7Y=DAmuQD#)s0U@IpArXmw&a3uhUO+i$3=6S4Ib#1bYZh9)o=3sSx! zpCMV}e47~YF80;H*>cc3x2cwsjp56NX{F7|LsZ=eNgF9;hL(h}R48Q`^!AN!5xreK z%WJ|aVdUIifR?n*k@M*V7Xdg8QBb&dw~gd8An>1{AO&suxox7iV(>IO&}?gh&`5$d z-<12hq@nacB`^_M3{*4-LQz?~rl5cb*bX|_uL2_>V9WP%V*-StPP2mufYobG27-bV zz;V+lRt>nwgUXQyuhaoT6wo{CcFBSnAt0)4?yLoB8bKSDmZBDrQUX!q*eC%&6a;Mh zxVZd5WHzAJI51cE=Uz4KCgf^U*|iE7Zdvs(D^ekE5_5Cm+x%EPDE4N2{3vq zjx|)CIMn^}EzdrY%Oi?{XD9K_wKOUXpkRB>{Lt&qZqy5tF|)JlYilz)T~I5#0rTKX zWQR?g`Nfl8AqwXw$KO7$aEFOM4AUe!{njybq*runB$X`EetsiK^SqG)f6hK}w@cd| zgMiSl8q;|vs^ugciWl9DgQf~}^NiyiSC$0N2$hzkK+R(%f}j+k(uWR&KXv(N5x#9J zCjcBYd$xb&CnXGZiC7--!~ame&@A8qq0ZW=-T*vO;}(Vw)G7Cp0-#n92B}eHJ8EYZ zY$Lwaeto{3;@nm`63X4x0i}hKJBHr!u@$Hchw?`c*RVruMZT)AOST!iM5lRC3wM}( zqE_^x`E5s<-_G9>MnXfrxi-<0so1;IL-uSL=ij~5=SA@mRiGg_q_x40#5%#q2E5k?w!@ZC)-)vf1ky78-v z*{?v4Z-(=vi4$C_2y5u^sQcb8G`L#BOu}@vjO=Shg;_buXxEg@6j>%; z8dHue^@JokPDH!k>Sv)aD2fWs=n_@6$YA1F}v2lFY-9SBvyN1XcvtiY4_hVoug> z#=kdb7n@7`1Az4xcrjCNc?o9kppXYr0TEUc#uaD0f^f zT<%uHR@kiO_r;@RKP&(9qtJXk&yvM}*3I9yf<-Ri7w*4Hjx{L}#C4S1#5hVUvqHC& zx2FQTNH6XmW7xw^6 z?U|5`-PN7@X{~9&O~HR%D3Vac%u-jdTe62dt@ojqdmy)%gU#Dl4(>k6*cL$|MrcQ7 zBv#Qk2L-xZQKq>Qnn)%j=4r%XY0`n$u|P|77|ZKJNsbYjMvAMDc+=ux-C_P7{Uz0kPVw$A`T)c=2g=* zjYWRtCw4!WlzuAtyjfLRRghT}U$n3pl4)z~YaBG}^vt)3T7tdg!aL#v@nfJQl!pLG z7#F4*W_9iCH1GxImqcYboYT+R**(>S0*oqyYEpPr_S5bQpN>bFvB4g5Hu`@7h$ZdlIEr@<# z>i3iusQ~V7i6X&uOe9}fa*H07-a@WiK4Z>v4tH@yxmK}=)RbgzXgQ~T8XCES+;DzA zSm_j1d)e&~-zaiBouuEbF1hl$g%CL!TD%3f$!4dsMHfZunhUWbHd-qm%hoD*2jIw88Lr=pen4EQ@aYvA;y!6uv1guH z9n#7hsP7i`sC^*3y@9}Om%@yEJt}y2etPerAwtArslo1dG>T1$A?{T*J&q}p;pGhf zy#G2|jOW0Y?D^OAWfff*#}Vgo=k1L}p?oXqjPlHlOll9R*|~bEr3dwU$3N9^BALVd zxaJ5n4D;@b!lxFel78&4yfXYf{0ROVF1M^#@7S!@n^7|yts^#QDssA(1 zjKEBP(s|P9O#7_vM7cVyeET%x%>7}NfxGu!FX1@h1ql~5dK&X}l6_neZjv;0Z&#DL z_s-`_)DJ%)DrqXSzw&xkxV+Q?*0xW`mQHR{$;~}a2&!BrnYihk>3a-6zLOj0+(?d>7ck=2<_!{i+tj z7MmlLJ=Iy*Ld>MH)#d!mkNKC6+x!X+$L2Lph@&D#E>n(^XkgcqvXcg*siJrD?<>j5 zt|F^YtoPVP=)$Fjx>GY>M;zPP_Ay4Y#kW%+>X>FBxr zx!+$x?9tJKv%Pk|c|Z0a@0Mr`*IsbEm51Mo}~fE`-^qm>zZaUfvCQlQ*TN|gQDw--b{tnp4TRt^I_piF5x;@cv}V{?YIhPL}ekP)C>czGOZyiUKhV&S+6V1;LZx#giuwUVIfjdG+k8_z0f#A$%JVL=-{9e`hz{ZCThh zlPYXmHZWL{Z_1Z6O*1t~(-gRpB*`Z{O(0Nl<%ejPOeVh~@OV6af%Ex1gp6~+j>lse zDmWgG#^qnH*U)G*;Q4$)Y?8&je^RM{z<~{LKA(ZIhb$cKr1PiK2{1Eabe_XqQ2Pg? zhcDagp|5-vcXH(~mrJy1&*4t4{PlVzD{IKY;V$rOT&-5t31Z#z9PR>}g5`2)JnC+@ zTeK_B;ZCMK>ZzhJolf<5I2?M_xpL2R9$&`PvDtgQ9u$j3SzHvxm(G>De|G+Uzmw6k z*_+KKRI61u91a@eOXte{?X=J3a@ZQnUxo3ddpYfG(NU>GMK4t0aDQv%XS10e4+aCT zx<4;?-EJ2Og@Qa&6~>qD<$^~|Kt-?BYC)}5gZ+N5F}`%J+%tQ7b<0C_NxR)H7@aG3 z@e^p8Ks~Vuhx=Q5emU2{W}{Qgr_PnT{-j+j7OCwTSTzf=35R=* znm`Bs2AQ*z1cvcfHUL`^gGVwck^fQ@^%ZiDK@kDkVjWkNlfF0PpVZu&}Ve9wnlw@Gx^EAG?!? zW}T03oD$K@2O+zFh!})KL<~YAA_gH5(M*&34;&pG;rRF%4-XGR9}tN|kjZ3_&1Ttq zMD(GIn_mM#cy)D!rKKe-FE0;m$TUr-hCxU~AI-S=H4ucGo13UstI%~_f9z50xlerX zIv5Nhl}fS4iRi-_H@~EpT_qE5E#b}*BAO;Icb3TPPI@nAXJ@#)ymW4_tgK*teVv^` z?}9-{?_z&{A15a#@caGF6z1aM0@v5q*xA`(=g|8EVfU9V6pKZaN+s0m^`Ud@SS*HI zE{A+R|8rdVQpazvAvbEZe;Q6tPn~lq8jV7hWjsDUqFgRxV`Br!WRjgku6dDPP7ppn zKX(p_D|0*^$KvAR&?gnEE}}-$w9YYcRqtK*-w-{XlRLULy=e=_H+-bp?Qre(si zEcj(V0>J=6;SkRwa_8ws_6+3Lzjl7e;Usra?cu^8js79AoRU#S>{PhZ?U?%+VeBdA9|~n)$%R~#d|bu zUyEN+`m2OSy)pCw(O47(tpIIX>lzZ;({=NyryU}q-$`VSDVaUFbNJ^W4h|1S=2z}> z4qx(LMvn-;{rwG*`3T~%_|S&Ls!REwGP0kuonxw{*mv-Xe@;YGWM@vml3_d>okJp< zUdu0$aogJV=n-L|P(YoYFw+;CR%n0szFq$ z6(piuH726zxNY1bok~N0(kE&snM_JOBf|a!b)mNKgYV)>O}T*-#6}dJ7?9{4nOX4 vC!(2T4*(_pJ5M5-c@n?!h=^w0cL4?fJh(hzD8Oue00000NkvXXu0mjfAn+PB diff --git a/core/res/res/drawable/status_bar_divider_shadow.9.png b/core/res/res/drawable/status_bar_header_background.9.png similarity index 93% rename from core/res/res/drawable/status_bar_divider_shadow.9.png rename to core/res/res/drawable/status_bar_header_background.9.png index ad58dbede5c0c276981b88d4345fee40a3d6c462..fa9a90c1ee450df44bf0e480696b1cede8fd6473 100644 GIT binary patch delta 150 zcmdliwpmQEGr-TCmrII^fq{Y7)59eQNV5X52?raHbn^W4cBA5QuIxz%IS&}{FrQ!O zoO1fjBwgd9UnlNbZ^KnP#fjzDiD?FI3z-B2S1}4`?fq`a7?m9?lYA#>?Nnw3WuaEq zX^*zqZ>+CQ-#N=sXhBNoH~aso^)qKitA(CpWDvU?ZF?f@i2=|m22WQ%mvv4FO#njA BH4Fd% delta 150 zcmdliwpmQEGr-TCmrII^fq{Y7)59eQNXGy%I|mz(Y+a_6vr%z5SN1eRp#}qIz(lz(Fy12eD1q9t>d-<-C@aH+OmR%S8Z0)0yn z?)L|HV*)q1|FHaCQ(?GiZrY}eOZNcH{{NquK~qyWXvwa9DnKrSr>mdKI;Vst09@!b Aq5uE@ diff --git a/core/res/res/drawable/status_bar_item_background_normal.9.png b/core/res/res/drawable/status_bar_item_background_normal.9.png index 6b7674048ee9c86256d71787c23b8cbbce834dba..b8e399d9d514a0064ca94a5718350457467f2a9d 100644 GIT binary patch delta 120 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 JPDHLkV1m$N6fgh) delta 3481 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 Hu0mjfDo>{1 diff --git a/core/res/res/drawable/title_bar_portrait.9.png b/core/res/res/drawable/title_bar_portrait.9.png new file mode 100644 index 0000000000000000000000000000000000000000..482d82e2f81dc9b260c937177886073272bfa1e9 GIT binary patch literal 4121 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 Xiz!7xK?$qg00000NkvXXu0mjf9OntW literal 0 HcmV?d00001 diff --git a/core/res/res/layout/always_use_checkbox.xml b/core/res/res/layout/always_use_checkbox.xml index 20fc4030b5944..5e6e3886facb6 100644 --- a/core/res/res/layout/always_use_checkbox.xml +++ b/core/res/res/layout/always_use_checkbox.xml @@ -16,7 +16,7 @@ - @@ -38,6 +37,5 @@ android:textAppearance="?android:attr/textAppearanceSmall" android:paddingLeft="36dip" android:visibility="gone" - android:layout_below="@id/alwaysUse" android:text="@string/clearDefaultHintMsg" /> - + diff --git a/core/res/res/layout/input_method.xml b/core/res/res/layout/input_method.xml index a21bbe899c574..1a701e9cc09a9 100644 --- a/core/res/res/layout/input_method.xml +++ b/core/res/res/layout/input_method.xml @@ -25,19 +25,28 @@ android:orientation="vertical" > - - - - - - + android:orientation="vertical" + > + + + + + + + + + - + android:layout_height="fill_parent" /> - + android:layout_height="2dip" /> - + android:layout_height="8dip" /> - - + android:id="@android:id/content" + android:fitsSystemWindows="true" + android:foregroundInsidePadding="false" + android:foregroundGravity="fill_horizontal|top" + android:foreground="?android:attr/windowContentOverlay" /> \ No newline at end of file diff --git a/core/res/res/layout/status_bar.xml b/core/res/res/layout/status_bar.xml index 9a6b7e8b2676b..0bc0dac42644c 100644 --- a/core/res/res/layout/status_bar.xml +++ b/core/res/res/layout/status_bar.xml @@ -97,7 +97,7 @@ android:gravity="center_vertical|left" android:paddingLeft="6px" android:paddingRight="6px" - android:textColor="#ff000000" + android:textColor="?android:attr/textColorPrimaryInverse" android:background="@drawable/statusbar_background" /> diff --git a/core/res/res/layout/status_bar_expanded.xml b/core/res/res/layout/status_bar_expanded.xml index a6a188e275c01..fd9d26e6eb163 100644 --- a/core/res/res/layout/status_bar_expanded.xml +++ b/core/res/res/layout/status_bar_expanded.xml @@ -31,12 +31,13 @@ android:paddingTop="3dp" android:paddingBottom="5dp" android:paddingRight="3dp" - android:background="@drawable/status_bar_divider_shadow" + android:background="@drawable/status_bar_header_background" > - - - - - - - - - + > + + - - - - + + + + + + + + + + + diff --git a/core/res/res/layout/status_bar_tracking.xml b/core/res/res/layout/status_bar_tracking.xml index 661ce86e2a9d6..aa3b733bdabd6 100644 --- a/core/res/res/layout/status_bar_tracking.xml +++ b/core/res/res/layout/status_bar_tracking.xml @@ -20,13 +20,12 @@ android:visibility="gone" android:focusable="true" android:descendantFocusability="afterDescendants" - android:background="@drawable/status_bar_background" android:paddingBottom="0px" android:paddingLeft="0px" android:paddingRight="0px" > - - - "Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Neomezeno" "Služba není zřízena." "Nelze změnit nastavení identifikace volajícího." + + + + + + + + + + "Hlas" "Data" "FAX" @@ -286,8 +296,10 @@ "Umožňuje povolit či zakázat aktualizace polohy prostřednictvím bezdrátového připojení. Aplikace toto nastavení obvykle nepoužívají." "přístup k vlastnostem Checkin" "Umožňuje čtení i zápis vlastností nahraných službou Checkin. Běžné aplikace toto nastavení obvykle nevyužívají." - "zvolit gadgety" - "Umožňuje aplikaci sdělit systému, které aplikace mohou použít které gadgety. Aplikace s tímto oprávněním mohou zpřístupnit osobní údaje jiným aplikacím. Není určeno pro normální aplikace." + + + + "změny stavu telefonu" "Umožňuje aplikaci ovládat telefonní funkce zařízení. Aplikace s tímto oprávněním může přepínat sítě nebo zapnout či vypnout bezdrátové připojení telefonu bez vašeho svolení." "zjistit stav telefonu" @@ -405,7 +417,8 @@ "Prosím vložte kartu SIM." "Síť je blokována" "Karta SIM je zablokována pomocí kódu PUK." - "Prosím kontaktujte podporu zákazníků." + + "Karta SIM je zablokována." "Odblokování karty SIM..." "%dkrát jste nakreslili nesprávné bezpečnostní gesto. "\n\n"Opakujte prosím akci za %d s." @@ -413,7 +426,8 @@ "Sekundy zbývající do dalšího pokusu: %d." "Zapomněli jste gesto?" "Gesta: Příliš mnoho pokusů" - "Chcete-li telefon odemknout,"\n"přihlaste se pomocí svého účtu Google" + + "Uživatelské jméno (e-mail)" "Heslo" "Přihlásit se" @@ -552,6 +566,8 @@ "Měsíčně" "Ročně" "Video nelze přehrát" + + "Toto video bohužel nelze přehrát." "OK" "dop." @@ -573,14 +589,14 @@ "d'. 'MMM' 'yyyy" "d'. 'MMM' 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "poledne" "Poledne" "půlnoc" "Půlnoc" - + "%B %-d, %Y" @@ -616,7 +632,7 @@ - + "neděle" "pondělí" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index cda8cbcd501d7..8619084493f0b 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -54,6 +54,16 @@ "Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt" "Dienst nicht eingerichtet." "Die Einstellung für die Anrufer-ID kann nicht geändert werden." + + + + + + + + + + "Sprachnotiz" "Daten" "FAX" @@ -286,8 +296,10 @@ "Ermöglicht die Aktivierung/Deaktivierung der Radio-Benachrichtigungen über Standort-Updates. Nicht für normale Anwendungen vorgesehen." "Auf Check-In-Eigenschaften zugreifen" "Ermöglicht den Schreib-/Lesezugriff auf vom Check-In-Service hochgeladene Elemente. Nicht für normale Anwendungen vorgesehen." - "Gadgets auswählen" - "Bei dieser Option meldet die Anwendung dem System, welche Gadgets von welcher Anwendung verwendet werden können. Mit dieser Genehmigung können Anwendungen anderen Anwendungen Zugriff auf persönliche Daten geben. Nicht für normale Anwendungen vorgesehen." + + + + "Telefonstatus ändern" "Ermöglicht einer Anwendung, die Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder das Radio des Telefons ein- und ausschalten, ohne Sie darüber zu informieren." "Telefonstatus lesen" @@ -405,7 +417,8 @@ "Bitte legen Sie eine SIM-Karte ein." "Netzwerk gesperrt" "SIM-Karte ist gesperrt. PUK-Eingabe erforderlich." - "Wenden Sie sich an den Kunden-Support." + + "SIM-Karte ist gesperrt." "SIM-Karte wird entsperrt..." "Sie haben Ihr Entsperrungsmuster %d-mal falsch gezeichnet. "\n\n"Versuchen Sie es in %d Sekunden erneut." @@ -413,7 +426,8 @@ "Versuchen Sie es in %d Sekunden erneut." "Muster vergessen?" "Zu viele Versuche!" - "Melden Sie sich zum Entsperren"\n"mit Ihrem Google-Konto an." + + "Nutzername (E-Mail)" "Passwort" "Anmelden" @@ -552,6 +566,8 @@ "Monatlich" "Jährlich" "Video kann nicht wiedergegeben werden." + + "Dieses Video kann leider nicht abgespielt werden." "OK" "AM" @@ -573,14 +589,14 @@ "d'. 'MMM' 'yyyy" "d'. 'MMM' 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "Mittag" "Mittag" "Mitternacht" "Mitternacht" - + "%-d. %B %Y" @@ -616,7 +632,7 @@ - + "Sonntag" "Montag" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 495f8aa10c8a9..30061e2d768fb 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -54,6 +54,16 @@ "El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: No restringido" "El servicio no se suministra." "El ID del emisor no se puede modificar." + + + + + + + + + + "Voz" "Datos" "FAX" @@ -286,8 +296,10 @@ "Permite habilitar/inhabilitar las notificaciones de actualización de la señal móvil. No está destinado al uso por parte de aplicaciones normales." "acceder a propiedades de registro" "Permite el acceso de lectura/escritura a las propiedades cargadas por el servicio de registro. No está destinado al uso por parte de aplicaciones normales." - "seleccionar gadgets" - "Permite a la aplicación indicar al sistema qué gadgets puede utilizar cada aplicación. Con este permiso, las aplicaciones pueden permitir a otras aplicaciones acceder a datos personales. No está destinado al uso por parte de aplicaciones normales." + + + + "modificar estado del teléfono" "Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, activar y desactivar la señal móvil, etc., sin necesidad de notificar al usuario." "leer el estado del teléfono" @@ -405,7 +417,8 @@ "Inserta una tarjeta SIM." "Bloqueada para la red" "La tarjeta SIM está bloqueada con el código PUK." - "Ponte en contacto con el servicio de atención al cliente." + + "La tarjeta SIM está bloqueada." "Desbloqueando tarjeta SIM..." "Has realizado %d intentos fallidos de creación de un patrón de desbloqueo. "\n\n"Inténtalo de nuevo dentro de %d segundos." @@ -413,7 +426,8 @@ "Espera %d segundos y vuelve a intentarlo." "¿Has olvidado el patrón?" "Se han realizado demasiados intentos incorrectos de creación del patrón." - "Para desbloquear el teléfono,"\n"accede a tu cuenta de Google" + + "Nombre de usuario (correo electrónico)" "Contraseña" "Acceder" @@ -552,6 +566,8 @@ "Mensualmente" "Anualmente" "No se puede reproducir el vídeo." + + "Este vídeo no se puede reproducir." "Aceptar" "a.m." @@ -573,14 +589,14 @@ "d' de 'MMM' de 'yyyy" "d' 'MMM', 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "mediodía" "Mediodía" "medianoche" "Medianoche" - + "%-d %B, %Y" @@ -616,7 +632,7 @@ - + "Domingo" "Lunes" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 8bd064d8b1d4f..b4b9318bef28a 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -54,6 +54,16 @@ "Par défaut, les identifiants d\'appelant ne sont pas restreints. Appel suivant : non restreint" "Ce service n\'est pas pris en charge." "Le paramètre Identifiant d\'appelant ne peut pas être modifié." + + + + + + + + + + "Voix" "Données" "Télécopie" @@ -286,8 +296,10 @@ "Permet l\'activation/la désactivation des notifications de mises à jour de la position géographique provenant de la radio. Les applications normales n\'utilisent pas cette fonctionnalité." "Accès aux propriétés d\'enregistrement" "Permet un accès en lecture/écriture à des propriétés envoyées par le service d\'inscription. Les applications normales n\'utilisent pas cette fonctionnalité." - "choisir les gadgets" - "Permet à l\'application de signaler au système quels gadgets peuvent être utilisés pour quelle application. Cette autorisation permet aux applications de fournir l\'accès à des données personnelles à d\'autres applications. Cette option n\'est pas utilisée par les applications standard." + + + + "Modification de l\'état du téléphone" "Permet à une application de contrôler les fonctionnalités téléphoniques de l\'appareil. Une application bénéficiant de cette autorisation peut changer de réseau, éteindre et allumer la radio du téléphone, etc., sans vous en avertir." "Lecture de l\'état du téléphone" @@ -403,17 +415,19 @@ "Aucune carte SIM n\'a été trouvée." "Aucune carte SIM n\'est insérée dans le téléphone." "Insérez une carte SIM." - "Réseau bloqué" + "Réseau verrouillé" "La carte SIM est verrouillée par code PUK." - "Veuillez contacter l\'assistance clientèle." - "La carte SIM est bloquée." + + + "Téléphone verrouillé" "Déblocage de la carte SIM..." "Vous avez mal reproduit le motif de déverrouillage %d fois. "\n\n"Veuillez réessayer dans %d secondes." "Vous avez mal saisi le motif de déverrouillage %d fois. Au bout de %d tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans %d secondes." "Réessayez dans %d secondes." "Motif oublié ?" "Trop de tentatives de motif !" - "Pour débloquer votre téléphone,"\n"connectez-vous à l\'aide de votre compte Google" + + "Nom d\'utilisateur (e-mail)" "Mot de passe" "Se connecter" @@ -551,6 +565,8 @@ "Tous les mois" "Tous les ans" "Échec de la lecture de la vidéo" + + "Désolé, impossible de lire cette vidéo." "OK" "AM" @@ -572,13 +588,13 @@ "d' 'MMM' 'yyyy" "d' 'MMM' 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "midi" "Midi" "minuit" "Minuit" "%-d %B" - + "%-d %B %Y" @@ -613,7 +629,7 @@ "%-d %b" - + "dimanche" "lundi" @@ -806,6 +822,8 @@ + + diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index b4cf458f28a88..f987ae2d586c5 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -54,6 +54,16 @@ "ID chiamante generalmente non limitato. Prossima chiamata: non limitato" "Servizio non fornito." "Impossibile modificare l\'impostazione dell\'ID del chiamante." + + + + + + + + + + "Voce" "Dati" "FAX" @@ -286,8 +296,10 @@ "Consente l\'attivazione/disattivazione delle notifiche di aggiornamento della posizione dal segnale cellulare. Da non usare per normali applicazioni." "accesso a proprietà di archiviazione" "Consente l\'accesso di lettura/scrittura alle proprietà caricate dal servizio di archiviazione. Da non usare per normali applicazioni." - "scegliere gadget" - "Consente all\'applicazione di indicare al sistema quali gadget possono essere utilizzati e da quale applicazione. Con questa autorizzazione, le applicazioni possono consentire ad altre applicazioni di accedere a dati personali. Da non usare per normali applicazioni." + + + + "modifica stato del telefono" "Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, attivare e disattivare il segnale cellulare e così via, senza alcuna notifica." "lettura stato del telefono" @@ -405,7 +417,8 @@ "Inserisci una SIM." "Rete bloccata" "La SIM è bloccata tramite PUK." - "Contatta il servizio clienti." + + "La SIM è bloccata." "Sblocco SIM..." "%d tentativi di inserimento della sequenza di sblocco. "\n\n"Riprova fra %d secondi." @@ -413,7 +426,8 @@ "Riprova fra %d secondi." "Hai dimenticato la sequenza?" "Troppi tentativi di inserimento della sequenza." - "Per sbloccare,"\n"accedi tramite il tuo account Google" + + "Nome utente (email)" "Password" "Accedi" @@ -552,6 +566,8 @@ "Mensilmente" "Annualmente" "Impossibile riprodurre il video" + + "Spiacenti. Impossibile riprodurre il video." "OK" "AM" @@ -573,14 +589,14 @@ "MMM' 'd', 'yyyy" "d' 'MMM' 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "mezzogiorno" "Mezzogiorno" "mezzanotte" "Mezzanotte" - + "%B %-d, %Y" @@ -616,7 +632,7 @@ - + "Domenica" "Lunedì" @@ -725,7 +741,7 @@ "L\'attività %1$s (nel processo %2$s) non risponde." "L\'applicazione %1$s (nel processo %2$s) non risponde." "Il processo %1$s non risponde." - "Forza chiusura" + "Termina" "Attendi" "Debug" "Seleziona un\'azione per il testo" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 2a21bd3fdbaff..25d906f17a57b 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -54,6 +54,16 @@ "既定: 発信者番号通知、次の発信: 通知" "提供可能なサービスがありません。" "発信者番号の設定は変更できません。" + + + + + + + + + + "音声" "データ" "FAX" @@ -69,7 +79,7 @@ "{0}:転送できません" "OK" "ウェブページにエラーがあります。" - "URLが見つかりませんでした。" + "URLが見つかりません。" "このサイトの認証方式には対応していません。" "認証できませんでした。" "プロキシサーバーを使用した認証に失敗しました。" @@ -279,15 +289,17 @@ "ハードウェアのテスト" "ハードウェアのテストのためにさまざまな周辺機器を制御することをアプリケーションに許可します。" "電話番号発信" - "アプリケーションが電話を自動発信することを許可します。悪意のあるアプリケーションが意図しない電話をかけて料金が発生する恐れがあります。緊急呼への発信は許可しません。" + "電話番号の自動発信をアプリケーションに許可します。悪意のあるアプリケーションが意図しない電話をかけて料金が発生する恐れがあります。緊急通報への発信は許可しません。" "電話番号発信" - "緊急呼を含めあらゆる電話番号に自動発信することをアプリケーションに許可します。悪意のあるアプリケーションが緊急サービスに不正な通報をする恐れがあります。" + "緊急通報を含めあらゆる電話番号に自動発信することをアプリケーションに許可します。悪意のあるアプリケーションが緊急サービスに不正な通報をする恐れがあります。" "位置情報の更新通知" "無線通信からの位置更新通知を有効/無効にすることを許可します。通常のアプリケーションでは使用しません。" "チェックインプロパティへのアクセス" "チェックインサービスがアップロードしたプロパティへの読み書きを許可します。通常のアプリケーションでは使用しません。" - "ガジェットの選択" - "特定のアプリケーションで使用可能なガジェットをシステムに指定することをアプリケーションに許可します。この許可を受けたアプリケーションは、他のアプリケーションに個人データへのアクセスを許可することができます。通常のアプリケーションでは使用しません。" + + + + "端末ステータスの変更" "端末の電話機能のコントロールをアプリケーションに許可します。アプリケーションは、ネットワークの切り替え、携帯電話の無線通信のオン/オフなどを通知せずに行うことができます。" "端末ステータスの読み取り" @@ -316,7 +328,7 @@ "APNのプロキシやポートなどのAPN設定の変更をアプリケーションに許可します。" "ネットワーク接続の変更" "ネットワークの接続状態の変更をアプリケーションに許可します。" - "バックグラウンドデータ使用の設定の変更" + "バックグラウンドデータ使用設定の変更" "バックグラウンドデータ使用の設定の変更をアプリケーションに許可します。" "Wi-Fi状態の表示" "Wi-Fi状態に関する情報の表示をアプリケーションに許可します。" @@ -388,13 +400,13 @@ "PINコードを入力" "PINコードが正しくありません。" "ロックを解除するにはMENU、0キーの順に押します。" - "緊急呼番号" + "緊急通報番号" "(サービス登録なし)" "画面ロック中" - "MENUキーでロック解除(または緊急呼)" + "MENUキーでロック解除(または緊急通報)" "MENUキーでロック解除" "ロックを解除するパターンを入力" - "緊急呼" + "緊急通報" "一致しました" "やり直してください" @@ -405,7 +417,8 @@ "SIMカードを挿入してください。" "ネットワークがロックされました" "SIMカードはPUKでロックされています。" - "お客様サポートにお問い合わせください。" + + "SIMカードはロックされています。" "SIMカードのロック解除中..." "ロック解除のパターンは%d回とも正しく指定されていません。"\n\n"%d秒後にもう一度指定してください。" @@ -413,7 +426,8 @@ "%d秒後にやり直してください。" "パターンを忘れた場合" "パターンのエラーが多すぎます" - "ロックを解除するには、"\n"Googleアカウントでログインしてください。" + + "ユーザー名 (メール)" "パスワード" "ログイン" @@ -427,7 +441,7 @@ "通知を消去" "通知なし" - "継続中" + "操作中" "通知" @@ -441,7 +455,7 @@ "再起動" "ページ「%s」の記述:" "JavaScript" - "このページから移動しますか?"\n\n"%s"\n\n"続行する場合は[OK]、今のページに残る場合は[キャンセル]を選択してください。" + "このページから移動しますか?"\n\n"%s"\n\n"移動する場合は[OK]、今のページに残る場合は[キャンセル]を選択してください。" "確認" "このパスワードをブラウザで保存しますか?" "今は保存しない" @@ -498,7 +512,7 @@ "1分前" - "%d分後" + "%d分前" "1時間前" @@ -552,6 +566,8 @@ "毎月" "毎年" "動画を再生できません" + + "この動画は再生できません。" "OK" "AM" @@ -565,22 +581,22 @@ "%3$s%2$s%1$s" "%3$s%2$s" "%3$s%1$s" - "%1$s%2$s" - "%1$s%2$s" + "%1$s %2$s" + "%1$s %2$s" "%2$s%1$s" "yyyy'/'MMMM'/'d" "yyyy'年'MMMM'月'd'日'" "MMM'/'d' 'yyyy'年'" "d'/'MMM'/'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "正午" "正午" "午前0時" "午前0時" - + "%Y%B%-d日" @@ -616,7 +632,7 @@ - + "日曜日" "月曜日" @@ -632,20 +648,20 @@ "(木)" "(金)" "(土)" - "(日)" - "(月)" - "(火)" - "(水)" - "(木)" - "(金)" - "(土)" - "(日)" + "日" + "月" + "火" + "水" + "木" + "金" + "土" + "日" "月" - "(火)" + "火" "水" - "(木)" + "木" "金" - "(土)" + "土" "日" "月" "火" @@ -712,7 +728,7 @@ "注意" "オン" "オフ" - "操作の完了に使用" + "アプリケーションを選択" "常にこの操作で使用する" "ホームの[設定]>[アプリケーション]>[アプリケーションの管理]でデフォルト設定をクリアします。" "操作の選択" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 8fc7d123931d8..faa1267cfb484 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -54,6 +54,16 @@ "발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한되지 않음" "서비스가 준비되지 않았습니다." "발신자 번호 설정을 변경할 수 없습니다." + + + + + + + + + + "음성" "데이터" "팩스" @@ -286,8 +296,10 @@ "무선의 위치 업데이트 알림을 활성화하거나 비활성화할 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다." "체크인 속성 액세스" "체크인 서비스에서 업로드한 속성에 대한 읽기/쓰기 액세스를 허용합니다. 일반 응용프로그램에서는 사용하지 않습니다." - "가젯 선택" - "어느 응용프로그램이 어느 가젯을 사용할 수 있는지 시스템에 알려 주는 권한을 본 응용프로그램에 부여합니다. 이 권한을 사용하면 응용프로그램이 개인 데이터에 대한 액세스 권한을 다른 응용프로그램에 제공할 수 있습니다. 일반 응용프로그램은 이 권한을 사용할 수 없습니다." + + + + "전화기 상태 수정" "응용프로그램이 장치의 전화 기능을 제어할 수 있습니다. 이 권한을 갖는 응용프로그램은 사용자에게 알리지 않고 네트워크를 전환하거나, 전화 무선 기능을 켜고 끌 수 있습니다." "전화기 상태 읽기" @@ -405,7 +417,8 @@ "SIM 카드를 삽입하세요." "네트워크 잠김" "SIM 카드의 PUK가 잠겨 있습니다." - "고객지원팀에 문의하세요." + + "SIM 카드가 잠겨 있습니다." "SIM 카드 잠금해제 중..." "잠금해제 패턴을 %d회 잘못 가져왔습니다. "\n\n"%d초 후에 다시 시도하세요." @@ -413,7 +426,8 @@ "%d초 후에 다시 입력하세요." "패턴을 잊으셨나요?" "패턴을 너무 많이 시도했습니다." - "잠금해제하려면"\n"Google 계정으로 로그인하세요." + + "사용자 이름(이메일)" "비밀번호" "로그인" @@ -552,6 +566,8 @@ "매월" "매년" "동영상 재생 안 됨" + + "죄송합니다. 동영상을 재생할 수 없습니다." "확인" "AM" @@ -573,14 +589,14 @@ "MMM' 'd', 'yyyy" "d' 'MMM', 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "정오" "정오" "자정" "자정" - + "%Y, %B %-d" @@ -616,7 +632,7 @@ - + "일요일" "월요일" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index c1944a45d3a03..61b89282a75e1 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -54,6 +54,16 @@ "Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset" "SIM-kortet er ikke tilrettelagt for tjenesten." "Kunne ikke endre innstilling for nummervisning." + + + + + + + + + + "Tale" "Data" "Fax" @@ -286,8 +296,10 @@ "Lar applikasjonen slå av/på varsling om plasseringsendringer fra radioen. Ikke ment for vanlige applikasjoner." "få tilgang til egenskaper for innsjekking" "Gir lese- og skrivetilgang til egenskaper lastet opp av innsjekkingstjenesten. Ikke ment for vanlige applikasjoner." - "velg gadgeter" - "Lar applikasjonen fortelle systemet hvilke gadgeter som kan brukes av hvilke applikasjoner. Med denne rettigheten kan applikasjoner andre applikasjoner tilgang til personlig data. Ikke ment for vanlige applikasjoner." + + + + "endre telefontilstand" "Lar applikasjonen kontrollere telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan endre nettverk, slå telefonens radio av eller på og lignende uten noensinne å varsle brukeren." "lese telefontilstand" @@ -405,7 +417,8 @@ "Sett inn et SIM-kort." "Nettverk ikke tillatt" "SIM-kortet er PUK-låst." - "Vennligst ring kundeservice." + + "SIM-kortet er låst." "Låser opp SIM-kort…" "You have incorrectly drawn your unlock pattern %d times. "\n\n"Please try again in %d seconds." @@ -413,7 +426,8 @@ "Prøv igjen om %d sekunder." "Glemt mønsteret?" "Too many pattern attempts!" - "To unlock,"\n"sign in with your Google account" + + "Username (email)" "Password" "Sign in" @@ -552,6 +566,8 @@ "En gang i måneden" "En gang i året" "Cannot play video" + + "Sorry, this video cannot be played." "OK" "AM" @@ -573,14 +589,14 @@ "MMM' 'd', 'yyyy" "d'. 'MMM' 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "middag" "Middag" "midnatt" "Midnatt" - + "%-d. %B %Y" @@ -616,7 +632,7 @@ - + "søndag" "mandag" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 725e369c16f08..2a67cd174641d 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -54,6 +54,16 @@ "Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: onbeperkt." "Service niet voorzien." "De instelling voor beller-id kan niet worden gewijzigd." + + + + + + + + + + "Spraak" "Gegevens" "FAX" @@ -286,8 +296,10 @@ "Hiermee kunnen updatemeldingen voor locaties van de radio worden ingeschakeld/uitgeschakeld. Niet voor gebruik door normale toepassingen." "toegang tot checkin-eigenschappen" "Hiermee wordt lees-/schrijftoegang gegeven tot eigenschappen die door de checkin-service zijn geüpload. Niet voor gebruik door normale toepassingen." - "gadgets kiezen" - "Hiermee kan een toepassing het systeem melden welke gadgets door welke toepassing kunnen worden gebruikt. Met deze toestemming kunnen toepassingen andere toepassingen toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale toepassingen." + + + + "telefoonstatus wijzigen" "Hiermee kan de toepassing de telefoonfuncties van het apparaat beheren. Een toepassing met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld." "telefoonstatus lezen" @@ -405,7 +417,8 @@ "Plaats een SIM-kaart." "Netwerk geblokkeerd" "SIM-kaart is geblokkeerd met PUK-code." - "Neem contact op met de klantenservice." + + "SIM-kaart is geblokkeerd." "SIM-kaart ontgrendelen..." "U heeft uw deblokkeringspatroon %d keer onjuist getekend. "\n\n"Probeer het over %d seconden opnieuw." @@ -413,7 +426,8 @@ "Probeer het over %d seconden opnieuw." "Patroon vergeten?" "Te veel patroonpogingen!" - "U moet zich aanmelden bij uw Google-account"\n"om te ontgrendelen" + + "Gebruikersnaam (e-mail)" "Wachtwoord" "Aanmelden" @@ -552,6 +566,8 @@ "Maandelijks" "Jaarlijks" "Video kan niet worden afgespeeld" + + "Deze video kan niet worden afgespeeld." "OK" "am" @@ -573,14 +589,14 @@ "MMM' 'd', 'yyyy" "d' 'MMM', 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "twaalf uur \'s middags" "Twaalf uur \'s middags" "middernacht" "Middernacht" - + "%B %-d, %Y" @@ -616,7 +632,7 @@ - + "Zondag" "Maandag" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 641d335d83346..8c1f61b4cf57b 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -54,6 +54,16 @@ "Identyfikator dzwoniącego ustawiony jest domyślnie na „nie zastrzeżony”. Następne połączenie: nie zastrzeżony" "Usługa nie jest świadczona." "Nie można zmienić ustawienia identyfikatora dzwoniącego." + + + + + + + + + + "Głos" "Dane" "FAKS" @@ -286,8 +296,10 @@ "Pozwala włączyć/wyłączyć powiadomienia o aktualizacji położenia przez radio. Nie wykorzystywane przez normalne aplikacje." "dostęp do właściwości usługi rezerwacji" "Pozwala na dostęp z uprawnieniami do odczytu/zapisu do właściwości przesłanych przez usługę rezerwacji. Nie wykorzystywane przez normalne aplikacje." - "wybieranie gadżetów" - "Zezwala aplikacjom na wskazywanie systemowi, które gadżety mogą być używane przez inne aplikacje. Z użyciem tego pozwolenia aplikacje mogą udzielać dostępu do danych osobistych innym aplikacjom. Nie jest ono przeznaczone dla zwykłych aplikacji." + + + + "zmiana stanu telefonu" "Pozwala aplikacji na kontrolowanie funkcji telefonu w urządzeniu. Aplikacja z tymi uprawnieniami może przełączać sieci, włączać i wyłączać radio itp. bez informowania użytkownika." "czytanie stanu telefonu" @@ -405,7 +417,8 @@ "Włóż kartę SIM." "Sieć zablokowana" "Karta SIM jest zablokowana kodem PUK." - "Skontaktuj się z działem obsługi klienta." + + "Karta SIM jest zablokowana." "Odblokowywanie karty SIM..." "Wzór odblokowania został nieprawidłowo narysowany %d razy. "\n\n"Spróbuj ponownie za %d sekund." @@ -413,7 +426,8 @@ "Spróbuj ponownie za %d sekund." "Zapomniałeś wzoru?" "Zbyt wiele prób narysowania wzoru!" - "Aby odblokować,"\n"zaloguj się na koncie Google" + + "Nazwa użytkownika (e-mail)" "Hasło" "Zaloguj" @@ -552,6 +566,8 @@ "Miesięcznie" "Co roku" "Nie można odtworzyć filmu wideo" + + "Niestety, nie można odtworzyć tego filmu wideo." "OK" "rano" @@ -573,14 +589,14 @@ "MMM' 'd', 'yyyy" "d' 'MMM', 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "południe" "Południe" "północ" "Północ" - + "%B %-d, %Y" @@ -616,7 +632,7 @@ - + "niedziela" "poniedziałek" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index ba886672130f5..4a99da51fc611 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -54,6 +54,16 @@ "Идентификатор звонящего по умолчанию не ограничен. Следующий вызов: не ограничен" "Услуга не предоставляется." "Нельзя изменить настройки идентификатора звонящего." + + + + + + + + + + "Голос" "Данные" "ФАКС" @@ -286,8 +296,10 @@ "Разрешает включение/отключение уведомлений о местоположении по радиосвязи. Не используется обычными приложениями." "открывать свойства проверки" "Разрешает доступ на чтение и запись к свойствам, загруженным службой проверки. Не используется обычными приложениями." - "выбирать гаджеты" - "Позволяет приложению сообщить системе, какие приложения могут использовать какие гаджеты. Это разрешение позволяет приложениям предоставлять другим приложениям доступ к личной информации. Не предназначено для использования обычными приложениями." + + + + "изменять состояние телефона" "Позволяет приложению управлять телефонными функциями устройства. Приложение с такими полномочиями может переключать сети, включать и выключать радиосвязь и т.д., не сообщая вам об этом." "считывать состояние телефона" @@ -405,7 +417,8 @@ "Вставьте SIM-карту." "Заблокирована сетью" "SIM-карта заблокирована PUK-кодом." - "Свяжитесь со службой поддержки." + + "SIM-карта заблокирована." "Разблокировка SIM-карты..." "Вы неправильно воспроизвели комбинацию разблокировки %d раз. "\n\n"Повторите попытку через %d сек." @@ -413,7 +426,8 @@ "Повторите попытку через %d сек." "Забыли комбинацию?" "Слишком много попыток ввести комбинацию!" - "Для разблокировки"\n"войдите с помощью своего аккаунта Google" + + "Имя пользователя (адрес электронной почты)" "Пароль" "Войти" @@ -552,6 +566,8 @@ "Ежемесячно" "Ежегодно" "Не удается воспроизвести видео" + + "К сожалению, это видео нельзя воспроизвести." "ОК" "AM" @@ -573,14 +589,14 @@ "d' 'MMM' 'yyyy" "d' 'MMM' 'yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "полдень" "Полдень" "полночь" "Полночь" - + "%-d %B %Y" @@ -616,7 +632,7 @@ - + "воскресенье" "понедельник" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 346e254533f18..b31c4f42c7182 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -54,6 +54,16 @@ "呼叫者 ID 默认情况下不受限制。下一个呼叫:不受限制" "未提供服务。" "不能更改呼叫者 ID 设置。" + + + + + + + + + + "语音" "数据" "传真" @@ -286,8 +296,10 @@ "允许启用/禁用来自收音机的位置更新通知。普通应用程序不能使用此权限。" "访问检入属性" "允许对检入服务上传的属性进行读/写访问。普通应用程序不能使用此权限。" - "选择小工具" - "允许应用程序告诉系统哪些应用程序可以使用哪些小工具。应用程序可以借此授予其他应用程序访问个人数据的权限。普通应用程序不能使用此权限。" + + + + "修改手机状态" "允许应用程序控制设备的手机功能。具有此权限的应用程序可能会切换网络,打开和关闭手机收音机以及类似操作,而不会通知您。" "读取手机状态" @@ -405,7 +417,8 @@ "请插入 SIM 卡。" "网络已锁定" "已对 SIM 卡进行 PUK 码锁定。" - "请联系客服部门。" + + "SIM 卡已被锁定。" "正在解锁 SIM 卡..." "您 %d 次错误地绘制了您的解锁图案。"\n\n"请在 %d 秒后重试。" @@ -413,7 +426,8 @@ "%d 秒后重试。" "忘记了图案?" "图案尝试次数太多!" - "要解锁,"\n"请用您的 Google 帐户登录" + + "用户名(电子邮件)" "密码" "登录" @@ -552,6 +566,8 @@ "每月" "每年" "无法播放视频" + + "很抱歉,此视频不能播放。" "确定" "上午" @@ -573,14 +589,14 @@ "yyyy' 年 'MMM' 月 'd' 日'" "yyyy' 年 'd' 月 'MMM' 日'" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "中午" "中午" "午夜" "午夜" - + "%Y%B%-d 日" @@ -616,7 +632,7 @@ - + "周日" "周一" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 6d4b8214c6f06..d88ca653b9718 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -54,6 +54,16 @@ "預設顯示本機號碼,下一通也顯示。" "服務未設定完成。" "本機號碼設定無法變更。" + + + + + + + + + + "語音" "資料" "傳真" @@ -286,8 +296,10 @@ "允許啟用/停用無線通訊位置更新通知。一般應用程式不會使用此功能。" "存取登機選項" "允許讀寫登機服務上傳的資料。一般應用程式不會使用此功能。" - "選擇小工具" - "允許應用程式告知系統哪些應用程式可以使用哪些小工具。擁有此權限的應用程式可以讓其他應用程式使用個人資料。一般應用程式不會使用此功能。" + + + + "修改手機狀態" "允許應用程式控制電話功能。擁有此權限的程式可自行切換網路、開關無線通訊功能。" "讀取手機狀態" @@ -405,7 +417,8 @@ "請插入 SIM 卡。" "網路已鎖定" "SIM 的 PUK 已鎖定。" - "請聯絡客服中心。" + + "SIM 卡已鎖定。" "解鎖 SIM 卡中..." "畫出解鎖圖形已錯誤 %d 次。"\n\n" 請在 %d 秒後再嘗試。" @@ -413,7 +426,8 @@ "%d 秒後再試一次。" "忘記解鎖圖形?" "解鎖圖形出錯次數過多!" - "若要解鎖,"\n"請以您的 Google 帳戶登入" + + "使用者名稱 (電子郵件)" "密碼" "登入" @@ -552,6 +566,8 @@ "每月" "每年" "無法播放影片" + + "抱歉,無法撥放此影片。" "確定" "上午" @@ -573,14 +589,14 @@ "MMM' 'd','yyyy" "d' 'MMM','yyyy" "h':'mm' 'a" - "H':'mm" + "HH':'mm" "中午" "中午" "午夜" "午夜" - + "%B %-d%Y" @@ -616,7 +632,7 @@ - + "星期日" "星期一" @@ -810,6 +826,8 @@ + + diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 899d109a3a877..485edca8ff6b1 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -620,12 +620,35 @@ Corresponds to {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE}. --> + + + + @@ -1372,7 +1395,8 @@ + The foreground drawable participates in the padding of the content if the gravity + is set to fill. --> @@ -1408,6 +1432,9 @@ edge, a right gravity will clip the left edge, and neither will clip both edges. --> + + @@ -3024,6 +3051,22 @@ + + + + + + + + + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 88c7b354d6fd0..c06c7c4d87b06 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1010,6 +1010,9 @@ + + + The caller ID setting cannot be changed. + + Restricted access changed + + Data service is blocked. + + Emergency service is blocked. + + Voice/SMS service is blocked. + + All voice/SMS services are blocked. + Voice @@ -1148,7 +1159,7 @@ PUK locked (Pin Unlock Kode) --> SIM card is PUK-locked. - Please contact Customer Care. + Please see the User Guide or contact Customer Care. SIM card is locked. diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index a1524104d4021..fb357a2c2c8be 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -154,12 +154,11 @@ - + + @@ -229,6 +231,7 @@ fills the entire screen --> @@ -303,21 +309,26 @@ @android:color/transparent @android:style/DialogWindowTitle true - @drawable/panel_separator + @null - - @@ -358,7 +369,7 @@ @android:style/DialogWindowTitle @android:color/transparent true - @drawable/panel_separator + @null @style/TextAppearance.Theme.Dialog.AppError diff --git a/docs/html/sdk/OLD_RELEASENOTES.jd b/docs/html/sdk/OLD_RELEASENOTES.jd new file mode 100644 index 0000000000000..77516818c047a --- /dev/null +++ b/docs/html/sdk/OLD_RELEASENOTES.jd @@ -0,0 +1,527 @@ +page.title=Release Notes for Older SDK Versions +@jd:body + +
+

Note: These are the release notes for the "early-look" SDK versions, released + before the full Android 1.0 release in September 2008. + Release notes for the Android 1.0 and later SDK versions are provided in the main + Release Notes document.

+
+ + + + +

Android 0.9 SDK Beta (r1)

+ +

This beta SDK release contains a large number of bug fixes and improvements from the early-look SDKs.  +The sections below describe the highlights of the release. + +

New Features and Notable Changes

+ +

Behavior and System Changes

+
    +
  • New Home screen and many user interface updates +
  • +
  • Minor changes to Activity lifecycle and task management +
  • +
  • New window option to request OpenGL acceleration for certain kinds of View structures +
  • +
+

+ + Significant API Changes +

+
    +
  • onFreeze(Bundle) renamed to onSaveInstanceState(Bundle), to better reflect the fact that it does not represent an actual change in application lifecycle +
  • +
  • IntentReceivers are now known as BroadcastReceivers (but still operate on Intents.) +
  • +
  • Various parts of the API cleaned up to use Intents instead of Bundles; Intent itself improved to reduce the need for separate payload Bundles.
  • +
  • ContentProvider Cursors have had significant changes to make them easier to create and remove certain data consistency bugs. +
  • +
  • Changes to menus to make them more flexible; also added context menus (similar to "right mouse button" menus) +
  • +
  • Changes to the Sensor API to make reading sensors more convenient and reduce the need to poll +
  • +
  • Improvements to the Camera API +
  • +
  • Significant changes to the Location API to make it easier to use and better self-documenting +
  • +
  • API cleanup on MapViews +
  • +
  • Performance-related changes to the MediaPlayer, as well as support for new types of ringtones +
  • +
  • Apache HTTPClient installation upgraded to 4.x of that API; 3.x version is removed +
  • +
  • HTTPClient 4.x removes multipart methods, include HttpMime which is an extension of Mime4j (http://james.apache.org/mime4j/index.html) in your project instead +
  • +
  • Improvements to WiFi and related networking +
  • +
  • New Preferences API to easily store small amounts of data +
  • +
  • Improvements to the Telephony API, including ability to obtain source number of incoming phone calls +
  • +
  • Variety of improvements to the View API +
  • +
  • Variety of improvements to component management, such as the ability to keep components private, better control over when processes are started, and ability to "alias" an Activity to more than one entry in AndroidManifest.xml +
  • +
  • Improvements to how the Browser and WebView, such as better control over content downloads +
  • +
  • A number of enhancements to XML layouts, such as the new <merge> tag +
  • +
  • Numerous improvements to the standard widgets +
  • +
  • Network access now requires that applications obtain a permission in their AndroidManifest.xml files. +
  • +
+

+ + Maps & Location +

+
    +
  • The MapView will require an API key on final Android 1.0 devices. This key can be obtained at no cost from Google, and will allow access to the full MapView API. In this release, the API key must be provided but can be any dummy value.  In the final 1.0-compatible SDKs, this will need to be a real key. +
  • +
  • The KML-based mock location provider supported in previous releases is no longer supported. In the current SDK, you can use the emulator console to send GPS fix updates to the emulator and applications running on it. Also, the DDMS tool provides an UI that you can use to easily upload GPX and KML files. DDMS handles playback of the KML or GPX tracks automatically.
  • +
+

+ ADT Plugin for Eclipse

+

The ADT Plugin that accompanies this SDK includes a preview of the Graphical Layout Editor. Files located in <project>/res/layout[-qualifiers]/ will be opened with the new layout editor. This is very much a work in progress, and provided here for preview purpose. The editor feature is subject to change. +

+
    +
  • Dual page editor with a WYSIWYG page (the graphical editor) and an XML page with content assist. +
  • +
  • The interactivity in the editor itself is limited to selection at the moment. Actions on the layout elements can be done from the following standard Eclipse views: Outline (add/remove/up/down), and Properties (editing of all the element properties with a tooltip in the status bar). +
  • +
  • Top part of the editor allows you to display the layout in different configurations (language, orientation, size, etc...), and different themes. + +
      +
    • All referenced resources (strings, bitmaps, etc...) are resolved based on the selected configuration/theme. +
    • +
    • A green check mark next to a resource qualifier indicates that the opened file matches the value of the qualifier. A warning sign indicates that the opened file does not specifies any value for this qualifier. +
    • +
    • If a different version of the opened layout matches the new configuration selection (in a different res/layout-qualifier folder) then the editor automatically switches to that new file. +
    • +
    +
  • +
  • Custom Views are supported, however if they do too much in their constructor/onDraw method, it may not work (the layout library used by the editor only includes a sub-part of the Android framework). Check the android console for errors/exceptions. +
  • +
+ +

Known issues/limitations for Graphical Layout Editor include:

+ +
    +
  • Font display is very close but not equals to on-device rendering since the font engine in Java slightly differs from the font engine in Android. This should not have any impact on your layouts. +
  • +
  • Creating new views in a relative layout automatically puts each new elements below each other using the layout_below attribute. However, until the layout file is saved, they will appear stacked on top of each other. +
  • +
  • Some XML based drawables don't draw. Fading in the scroll/list view appears as a white rectangle. Generally do not expect every single fancy drawing feature of the android framework to be supported in the layout editor (but we're working on it). +
  • +
  • Themes defined in the project are not added to the theme drop-down. +
  • +
  • No animation support! +
  • +
  • No support for WebView, MapView and SurfaceView. +
  • +
  • No UI support for <merge>, <include>, <ViewStub> elements. You can add these elements to your manifest using the xml editor only. +
  • +
  • If a layout fails to render in a way that prevents the whole editor from opening, you can: + +
      +
    • open that particular file in a different editor: right click the file in the package explorer and choose Open With... > XML editor +
    • +
    • completely disable the layout editor, by setting a system wide environment variable called ANDROID_DISABLE_LAYOUT to any value. +
    • +
    +
  • If a layout fails to render, check the android console (in the standard Eclipse Console view). Errors/Exceptions will be displayed in there. +
  • +
+ + +

Other ADT features/notes include:

+
    +
  • There is a new launch option for activity. You can choose to launch the default activity (finds an activity configured to show up in the home screen), or a specific activity, or none.
  • +
  • Normal Java resources (non Java files placed in package folders) are now properly packaged in the final package, and can be accessed through normal java API such as ClassLoader.getResourceAsStream()
  • +
  • Launch configuration now has an option to wipe emulator data on launch. This always asks for confirmation.
  • +
  • Launch configuration now has an option to disable the boot animation. This will let the emulator start faster on older computers.
  • +
  • Installation of application is now more robust and will notify of installation failure. Also installation is blocking, removing issues where ADT tried to launch the activity before the app was installed.
  • + +
+ +

Ant Build Tools

+ +
    +
  • External jar libraries are now directly supported by build.xml, just drop them in the libs directory.
  • +
+ +

Emulator

+ +
    +
  • The console port number of a given emulator instance is now displayed in its window's title bar.
  • +
  • You can define the console port number used by a given emulator instance. +To do so, start the instance with the '-port <port>' option and +specify which port the emulator should bind to for the console. <port> must be an *even* integer between 5554 and 5584 inclusive. The corresponding ADB port will be <port>+1.
  • +
  • The -adb-port command is deprecated. Please do not use it, as it will be removed soon and you cannot use both -port and -adb-port at the same time.
  • +
  • Voice/sms are automatically forwarded to other emulator instances running on the same machine, as long as you use their console port number as the destination phone number. For example, if you have two emulators running, the first one will typically use console port 5554, and the second one will use port 5556, dialing 5556 on the first emulator will generate an incoming call on the second emulator. You can also hold/unhold calls. This also works when sending SMS messages from one emulator to the other.
  • +
  • A new -scale <fraction> option allows you to scale the emulator window.
  • +
  • A new -no-boot-anim option tells the emulator to disable the boot animation. On slower systems, this can significantly reduce the time to boot the system in the emulator.
  • + +
+ +

+ Other Development Tools +

+ +

The SDK includes several new development tools, such as

+
    +
  • HierarchyViewer is a visual tool for inspecting and debugging your user interfaces and layout.
  • +
  • Draw 9-patch allows you to easily create a NinePatch graphic using a WYSIWYG editor.
  • +
  • The UI/Application Exerciser Monkey generates pseudo-random system and user events, for testing your application.
  • +
+

+ Application Signing +

+
    +
  • Starting with this release, Android .apk files must be cryptographically signed, or the system will reject them upon installation.  The purpose of this requirement is to securely and uniquely identify developers, so that the system can -- for example -- safely let multiple .apk files signed by the same developer share resources.  +
  • +
  • There are no requirements on the key used to sign .apk files;  locally-generated and self-signed keys are allowed.  There is no PKI, and developers will not be required to purchase certificates, or similar.   For developers who use the Eclipse/ADT plugin, application signing will be largely automatic.  Developers who do not use Eclipse/ADT can use the standard Java jarsigner tool to sign .apk files. +
  • +
+

+ Sample Code +

+
    +
  • LunarLander has been converted to render into a SurfaceView via a background Thread, for better performance. +
  • +
  • New sample: the source code for the now-obsolete Home screen from M5 is included as an example of how to construct a Home screen replacement. +
  • +
+

+ + Removed Functionality +

+
    +
  • Due to significant API changes in the upstream open-source project and due to the timeline of getting certain Bluetooth profile implementations certified, a comprehensive Bluetooth API will not be possible or present in Android 1.0. +
  • +
  • Due to the security risks inherent in accepting arbitrary data from "outside" the device, the data messaging facility of the GTalkService will not be present in Android 1.0.  The GTalkService will provide connectivity to Google's servers for Google Talk instant messaging, but the API has been removed from this release while we improve the service.  Note that this will be a Google-specific service and is not part of the core of Android. +
  • +
  • We know that these changes will affect many developers who have worked with the prior early looks at the SDK, and we are very sorry for the resulting inconvenience.  We look forward to the possibilty of restoring some or all of this functionality in a later version of the Android platform. +
  • +
+

+ + Miscellaneous +

+
    +
  • Many internal and non-public APIs have been removed from the documentation.  Classes and methods that are not present in the documentation are non-public and should not be used, even though they may appear in tools such as IDEs.  A future version of the SDK will ship with an android.jar file that contains only public classes, to help developers avoid accidentally using non-public APIs. +
  • +
  • A few extraneous APIs (such as unnecessary packages under java.awt) have been removed. +
  • +
  • Several additional tools are included, such as a utility for easily drawing 9-patch images. +
  • +
  • The DDMS utility has been refactored into library form. This is not of direct interest to application developers, but may be of interest to vendors interested in integrating the Android SDK into their products. Watch for more information about the ddmlib library soon. +
  • +
  • For performance and maintainability reasons, some APIs were moved into separate modules that must be explicitly included in the application via a directive in AndroidManifest.xml.  Notable APIs that fall into this category are the MapView, and the java.awt.* classes, which each now reside in separate modules that must be imported.  Developers who overlook this requirement will see ClassNotFoundExceptions that seem spurious. +
  • +
  • Developers who use 'adb push' to install applications must now use 'adb install', since the full package manager is now implemented. 'adb push' will no longer work to install .apk files. +
  • +
  • The emulator supports a variety of new options, and some existing options have been changed.  Please consult the updated emulator documentation for details. +
  • +
+ +

+ Resolved Issues +

+

+ The list below is not comprehensive, but instead highlights the most interesting fixes since the last SDK release. +

+
    +
  • More of the standard Android user applications are now included, such as the Music and Messaging applications. +
  • +
  • Many bug fixes to the Media Player +
  • +
  • Emulator performance is improved, especially for startup +
  • +
  • More internal APIs are removed from class documentation.  (However, this work is not quite yet complete.) +
  • +
  • It's now much easier to add media content to the SD card and have the ContentProvider locate and expose it to other applications. +
  • +
+ +

+ Known Issues +

+
    +
  • The final set of Intent patterns honored by Android 1.0 has not yet been fully documented.  Documentation will be provided in future releases. +
  • +
  • We regret to inform developers that Android 1.0 will not support 3.5" floppy disks. +
  • +
  • Unfortunately, the ability to play audio streams from memory (such as via an InputStream or Reader) will not be possible in Android 1.0.  As a workaround, we recommend that developers save media content to SD card and use MediaPlayer to play from a file URI, or embed a small HTTP server and play from a URI on localhost (such as http://127.0.0.1:4242/something). +
  • +
  • Android now supports modules or libraries that can be optionally linked into applications; a good example is the MapView, which has been moved into such a library. However, Android 1.0 will not support the ability for third-party developers to create such libraries for sharing with other applications. +
  • +
  • We believe that we have eliminated the problem with very long emulator startups on Windows, but had some trouble reproducing the issue.  We are interested in feedback from developers, if this issue persists. +
  • +
+ + + + + +

Version m5-rc15

+ +

New Features

+

m5-rc15 does not introduce any new features.

+ +

Resolved Issues

+
    +
  • 1012640: Incorrect handling of BMP images.
  • +
+ +

Known Issues

+

Unless otherwise noted, Known Issues from m5-rc14 also apply to m5-rc15.

+ + + + + +

Version m5-rc14

+ +

New Features

+ +

In addition to changes in the Android APIs, m5-rc14 also introduces changes to the Android Developer Tools:

+ +

emulator

+
    +
  • The Android emulator now support SD card images up to 128 GB in size. The previous limit was 2 GB.
  • +
+ +

DDMS

+
    +
  • Support for managing multiple devices has been integrated into DDMS. This should make it easier to debug applications that are run on multiple device scenarios.
  • +
+ +

ADT

+
    +
  • ADT now attempts to connect a debugger to any application that shows up + in the wait-for-debugger state, even if this application was not launched + from Eclipse. +

    + The connection is actually established only if there exists a project + in the Eclipse workspace that contains an AndroidManifest.xml + declaring a package matching the name of the process. + To force this connection from your code, use Debug.waitForDebugger(). Activities declaring that they require their own process through the + "process" attribute with a value like ":someProcess" will be + recognized and a debugger will be connected accordingly. + This should make it easier to debug intent receivers, services, + providers, and other activities not launched from the standard app + launcher.

  • +
  • ADT has launch modes for device target selection. Automatic mode will: 1) launch an emulator if no device is present, 2) automatically target the device if only one is connected, and 3) prompt the user if 2 or more are connected. Manual mode will always prompt the user.

  • +
  • ADT also contains the same support for multiple devices that has been introduced into DDMS.
  • +
+ +

AIDL

+
    +
  • AIDL files that import and reuse types is now supported by activityCreator.py and ADT.
  • +
+ +

traceview

+
    +
  • The traceview tool is now included in the SDK.
  • +
+ +

Resolved Issues

+ +

The following Known Issues from m3-rc20 have been resolved:

+
    +
  • 917572: The activityCreator created incorrect IntelliJ scripts
  • +
  • 917465: Unanswered incoming calls placed from the emulator console will result in an unfinished call UI if you press the call back button
  • +
  • 917247: dmtracedump and traceview tools are not available in the SDK
  • +
  • 912168: Extremely rapid or prolonged scrolling in the Maps application or MapsView will result in application errors
  • +
  • 905852: adb emits warnings about deprecated API use on Mac OS X 10.5
  • +
  • 905242: The Run dialog sometimes failed to show the Android Launcher
  • +
  • 901122: The focus ring in the browser is sometimes incorrect
  • +
  • 896274: On Windows, the emulator sometimes starts off-screen
  • +
  • 778432: Icons for newly installed applications do not display
  • +
+ +

Known Issues

+ +

The following are known issues in m5-rc14:

+ +
    +
  • 1017312: The emulator window size has been reduced slightly, to allow it to be fully visible on smaller screens. This causes a slight clipping of the HVGA emulator skin but does not affect its function.
  • +
  • 1021777: Setting a power requirement in a Criteria object passed to {@link android.location.LocationManager#getBestProvider getBestProvider()} will result in a value not being returned.
  • +
  • 1025850: Emulator failing to launch from the Eclipse plugin due to wrong custom command line parameters do not report the error anywhere and silently fails.
  • +
+ +

Unless otherwise noted, Known Issues from m3-rc20a also apply to m5-rc14.

+ + + + + +

Version m3-rc37a

+ +

Version m3-rc37a and ADT 0.3.3 were released on December 14, 2007.

+ +

New Features

+ +

Android Debug Bridge (ADB)

+
    +
  • Now supports multiple emulators on one host computer. Please note that you need to use the -data option when starting secondary emulators, to allow those instances to save their data across sessions. Also, DDMS does not yet support debugging on multiple emulators yet.
  • +
+ +

ADT Plugin for Eclipse

+
    +
  • Adds editor capabilities for working with Android manifest files, such as syntax highlighting and autocompletion. The editor capabilities require the Web Tools WST plugin for Eclipse, which is included in most Eclipse packages. Not having WST does not prevent the ADT plugin from working. If necessary, you can download and install WST from the Web Tools Project downloads page. To update directly from an Eclipse installation, you can add a remote update site with this URL: http://download.eclipse.org/webtools/updates . Note that installing WST on Eclipse 3.4 will require installing other packages, as detailed on the WTP downloads page. +
  • +
  • Now retries to launch the app on the emulator if it fails due to timing issues when the emulator is booting.
  • +
  • Adds support for loading custom skins from the <SDK>/lib/images/skins/ directory. The Skin dropdown in the Emulator tab is now built from the content of the skins/ directory in order to support developer-made skins.
  • +
  • Adds an Emulator control panel. This is a UI on top of the emulator console that allows you to change the state of the network and gsm connection, and to initiate incoming voice call. (This is also present in standalone DDMS.)
  • +
  • Adds support for referenced projects. Android projects will add to the apk package any code from referenced projects.
  • +
  • Eclipse console now warns if an .apk that is pushed to the device declares the same package as another already installed package.
  • +
  • Java classes generated by the Eclipse plugin are now marked as derived automatically, so that Team plugins do not consider them as regular source.
  • +
+ +

Emulator Console

+
    +
  • Now provides support for emulating inbound SMS messages. The ADT plugin and DDMS provide integrated access to +this capability. For more information about how to emulate inbound SMS from the console, +see SMS Emulation.
  • +
+ +

Emulator

+
  • The default emulator skin has been changed to HVGA-P from QVGA-L. For information +about emulator skins and how to load a specific skin when starting the emulator, see +Using Emulator Skins.
  • +
+ +

Resolved Issues

+ +

907947

+

adb -version now returns a version number.

+ +

917462

+

Audio on Windows is fixed and is no longer 'choppy'.

+ +

Removed Manifest File Locking on Mac OS X

+ +

ADT plugin now uses a custom java editor for R.java/Manifest.java, to make those files non-editable. This is to replace the current locking mechanism which causes issues on Mac OS (preventing projects from being deleted). Note that your project must recompile at least once for the lock to be removed from the files.

+ +

The following known issues noted in m3-rc20 are now fixed:

+

+

    +
  • 890937: Emulator does not support non-qwerty keyboards. +
  • 894618: adb shell may fail to connect when used the first time. +
  • 896274: On Windows, the emulator window may start off-screen. +
  • 899949: The emulator may fail to start with -useaudio on some environments. +
  • 912619: Emulator console listens on non-local ports 5554-5584. +
  • 917399: On Windows, running multiple emulator consoles can result in unexpected behavior when simulating incoming telephone calls. +
+

+ +

Known Issues

+ +

Unless otherwise noted, Known Issues from m3-rc22a also apply to m3-rc37a.

+ + + + + +

Version m3-rc22a

+ +

Version m3-rc22a and ADT 0.3.1 were released on November 16, 2007.

+ +

Resolved Issues

+ +

920067

+

The New Android Project wizard provided by ADT 0.3.1 now properly displays error messages when used with Eclipse 3.2 on Windows.

+ +

920045

+

The AndroidManifest.xml files generated by ADT 0.3.1 now include the XML element required for displaying the associated app in the "Applications" menu. If you have applications created with ADT 0.3.0, simply ensure that your AndroidManifest.xml file contains the following highlighted line:

+
+...
+    <intent-filter>
+        <action android:value="android.intent.action.MAIN" />
+        <category android:value="android.intent.category.LAUNCHER" />
+    </intent-filter>
+...
+
+ +

920098

+

ADT 0.3.1 is now compatible with Eclipse 3.4.

+ +

920282

+

Fixes a NullPointerException that is thrown in certain situations with the DDMS perspective in Eclipse.

+ +

918637

+

Address a keyboard lock-up issue when using adb on Mac OS X 10.4 and 10.5.

+ +

Known Issues

+ +

Unless otherwise noted, known issues from m3-rc20a also apply to m3-rc22a.

+ + + +

Version m3-rc20a

+

Known Issues

+ +

The following are known issues in m3-rc20a:

+ +

778432 - Resolved in m5

+

In certain circumstances, icons for newly installed applications do not display as expected.

+ +

890937 - Resolved in m3-rc37a

+

The emulator currently does not support non-QWERTY keyboards.

+ +

894618 - Resolved in m3-rc37a

+

The adb shell command may fail to connect when used for the first time.

+ +

896274 - Resolved in m5

+

On Windows, the emulator screen will sometimes show up off-screen when it is started. The workaround for this is to right-click on the emulator taskbar entry, select Move, and move the window using keyboard arrow keys

+ +

899949 - Resolved in m3-rc37a

+

The emulator may fail to start when using the -useaudio in some environments

+ +

901122 - Resolved in m5

+

The focus ring shown in the browser may sometimes not properly wrap links.

+ +

905242 - Resolved in m5

+

On Mac OS X 10.5, the Eclipse plugin's Run Dialog may sometimes fail to show the option to select the Android Launcher.

+ +

905852 - Resolved in m5

+

On Mac OS X 10.5, adb will emit warnings about deprecated API use when first used.

+ +

912168 - Resolved in m5

+

extremely rapid or prolonged scrolling in the Maps application or in a MapView will result in application errors.

+ +

912619 - Resolved in m3-rc37a

+

The emulator console listens for connections on ports 5554-5587. Future versions will only accept connections from localhost. It is recommend that you use a firewall to block external connections to those ports on your development machine.

+ +

912849

+

On Mac OS X 10.4, the emulator may hang if started in the background (i.e. ./emulator &).

+ +

914692

+

On Mac OS X 10.5, the emulator will emit warnings about deprecated API use when started from the command line.

+ +

917247 - Resolved in m5

+

The dmtracedump and traceview tools are not available in the SDK.

+ +

917399 - Resolved in m3-rc37a

+

On Windows, running multiple emulator consoles can result in unexpected behavior when simulating incoming telephone calls.

+ +

917465 - Resolved in m5

+

Unanswered incoming calls placed from the emulator console, will result in an unfinished call UI if you press the call back button.

+ +

917572 - Resolved in m5

+

Using activityCreator with the --ide intellij option creates IntelliJ scripts with incorrect documentation location specified. To correct, change value for the <JAVADOC> element in the generated .ipr file from file://.../docs/framework to file://.../docs/reference.

+ +

917579

+

On Ubuntu 7.10 (Gusty), the Eclipse package installed by the apt-get install eclipse command uses java-gcj by default. This configuration is not compatible with the Android Eclipse plugin (ADT) and will result in "Class not found" errors whenever you access an ADT feature.

+

The resolution for this issue is to install a Sun JDK

+
sudo update-java-alternatives --jre java-1.5.0-sun
+

and then configure Eclipse to use it by exporting the following environment variable:

+
export JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun
+

or by adding following to your .eclipse/eclipserc file:

+
JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun
+ diff --git a/docs/html/sdk/older_releases.jd b/docs/html/sdk/older_releases.jd new file mode 100644 index 0000000000000..ff57a36ec3922 --- /dev/null +++ b/docs/html/sdk/older_releases.jd @@ -0,0 +1,234 @@ +page.title=Older Releases +@jd:body + +
+ NOTICE: +

The SDKs listed on this page are "early-look" versions that were released in + the year preceding the full release of Android 1.0 in September 2008. Because + these early-look SDKs were released before the Android 1.0 API specification was + finalized, they do not provide a compliant Android execution environment. + Consequently, applications that you develop in these SDKs will not be able to + run on any Android-powered devices.

+ +

If you have an older application that you built in one of the early-look SDKs, + you must migrate it to the Android + 1.0 SDK (or later release) before you will be able to deploy it to + an Android-powered device. To help with this migration, each SDK package below + provides information about API changes from the previous version. You can find + the migration information in the documentation included in each SDK package.

+ +

If you are just getting started developing on Android, do not use one of these early-look + SDKs. Instead, develop using the most current + SDK release available, to ensure that your applications will be compatible + with Android-powered devices.

+
+ + + + +

Android 0.9 SDK beta

+

August 18, 2008 - Release Notes

+
- +
+ + + + + + + + + + + + + + + + + + + + + + + + +
PlatformPackageSizeMD5 Checksum
Windows +android-sdk-windows-0.9_beta.zip93,126,573 bytes305031ad8335d1b6040bdd5a65349d6d
Mac OS X (intel) +android-sdk-mac_x86-0.9_beta.zip91,374,464 bytes9a6969159091cede46302e11049fe3ca
Linux (i386) +android-sdk-linux_x86-0.9_beta.zip91,821,068 bytes077e5ef549dd9c5be54bd88e6a8e196c
+ + + + +

Version m5-rc15

+

March 3, 2008 - Release Notes

+ + + + + + + + + + + + + + + + + + + + + + + + + +
PlatformPackageSizeMD5 Checksum
Windows +android-sdk_m5-rc15_windows.zip79 MBecce40bc50201886d95ba2690cdbc5ce
Mac OS X (intel) +android-sdk_m5-rc15_mac-x86.zip76 MB45a6385bbc1b2cb295409cfc81fb04b4
Linux (i386) +android-sdk_m5-rc15_linux-x86.zip76 MBe913f785afecdeed34c30639fd8c5862
+ + + + +

Version m5-rc14

+

February 12, 2008 - Release Notes

+ + + + + + + + + + + + + + + + + + + + + + + + + +
PlatformPackageSizeMD5 Checksum
Windows +android-sdk_m5-rc14_windows.zip79 MBecc75c1e69588350634ca25867ce05a0
Mac OS X (intel) +android-sdk_m5-rc14_mac-x86.zip76 MB844c80d0adb1a326f5a9fff262c61efc
Linux (i386) +android-sdk_m5-rc14_linux-x86.zip76 MBf8b863c8a880afe9bb84124f5976aab1
+ + + + +

Version m3-rc37a

+

December 14, 2007 - Release Notes

+ + + + + + + + + + + + + + + + + + + + + + + + + +
PlatformPackageSizeMD5 Checksum
Windows +android_sdk_windows_m3-rc37a.zip58 MB5db5aea20a2c2f010baefc4b1091a575
Mac OS X (intel) +android_sdk_darwin_m3-rc37a.zip54 MB0b22e73fbd07b4af4009387afce3a37f
Linux (i386) +android_sdk_linux_m3-rc37a.zip54 MB41285beecc4f9926e6ecf5f12610b356
+ + + + +

Version m3-rc22a

+

November 16, 2007 - Release Notes

+ + + + + + + + + + + + + + + + + + + + + + + + + +
PlatformPackageSizeMD5 Checksum
Windows +android_sdk_windows_m3-rc22a.zip59 MBaa3dee05a9872752a3bc4efd0f93e98b
Mac OS X (intel) +android_sdk_darwin_m3-rc22a.zip55 MB0547f45614ad94c3af22c3c0aa6f709f
Linux (i386) +android_sdk_linux_m3-rc22a.zip55 MB84b3455de5cdfd841a172c13d24c382e
+ + + + +

Version m3-rc20a

+

November 12, 2007 - Release Notes

+ + + + + + + + + + + + + + + + + + + + + + + + + +
PlatformPackageSizeMD5 Checksum
Windows +android_sdk_windows_m3-rc20a.zip59 MBa404b875708df7339ba77bdf2e08dc06
Mac OS X (intel) +android_sdk_darwin_m3-rc20a.zip55 MB8fc29aeaa45eda84bfac854ebd02a6da
Linux (i386) +android_sdk_linux_m3-rc20a.zip55 MB9196759df9b69cd89a220b156f133364
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index 76c1c84ea07ba..9a5a18b39b30b 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -30,6 +30,7 @@ diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h index 78d76219baf85..b9ea0c66e3010 100644 --- a/include/media/mediarecorder.h +++ b/include/media/mediarecorder.h @@ -104,7 +104,8 @@ enum media_recorder_error_type { // enum media_recorder_info_type { MEDIA_RECORDER_INFO_UNKNOWN = 1, - MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800 + MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800, + MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801 }; // ---------------------------------------------------------------------------- diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index 1991aa74c71bd..bda969ce83251 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -64,7 +64,8 @@ struct audio_track_cblk_t uint16_t waitTimeMs; // Cumulated wait time // Padding ensuring that data buffer starts on a cache line boundary (32 bytes). // See AudioFlinger::TrackBase constructor - int32_t Padding[3]; + int32_t Padding[1]; + // Cache line boundary audio_track_cblk_t(); uint32_t stepUser(uint32_t frameCount); diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index 7d3fcf2a837d9..d01d83f831690 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -814,7 +814,7 @@ struct ResTable_config ORIENTATION_ANY = 0x0000, ORIENTATION_PORT = 0x0001, ORIENTATION_LAND = 0x0002, - ORIENTATION_SQUARE = 0x0002, + ORIENTATION_SQUARE = 0x0003, }; enum { diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index 5652b285ade08..9ba7f90f956e0 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -58,6 +58,9 @@ namespace android { +static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n"; +static const char* kHardwareLockedString = "Hardware lock is taken\n"; + //static const nsecs_t kStandbyTimeInNsecs = seconds(3); static const unsigned long kBufferRecoveryInUsecs = 2000; static const unsigned long kMaxBufferRecoveryInUsecs = 20000; @@ -195,7 +198,7 @@ AudioFlinger::~AudioFlinger() #ifdef WITH_A2DP // setA2dpEnabled_l() must be called with AudioFlinger::mLock held void AudioFlinger::setA2dpEnabled_l(bool enable) -{ +{ SortedVector < sp > tracks; SortedVector < wp > activeTracks; @@ -243,12 +246,6 @@ bool AudioFlinger::streamForcedToSpeaker(int streamType) streamType == AudioSystem::NOTIFICATION); } -bool AudioFlinger::streamDisablesA2dp(int streamType) -{ - return (streamType == AudioSystem::VOICE_CALL || - streamType == AudioSystem::BLUETOOTH_SCO); -} - status_t AudioFlinger::dumpClients(int fd, const Vector& args) { const size_t SIZE = 256; @@ -301,18 +298,39 @@ status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector& args return NO_ERROR; } +static bool tryLock(Mutex& mutex) +{ + bool locked = false; + for (int i = 0; i < kDumpLockRetries; ++i) { + if (mutex.tryLock() == NO_ERROR) { + locked = true; + break; + } + usleep(kDumpLockSleep); + } + return locked; +} + status_t AudioFlinger::dump(int fd, const Vector& args) { if (checkCallingPermission(String16("android.permission.DUMP")) == false) { dumpPermissionDenial(fd, args); } else { - bool locked = false; - for (int i = 0; i < kDumpLockRetries; ++i) { - if (mLock.tryLock() == NO_ERROR) { - locked = true; - break; - } - usleep(kDumpLockSleep); + // get state of hardware lock + bool hardwareLocked = tryLock(mHardwareLock); + if (!hardwareLocked) { + String8 result(kHardwareLockedString); + write(fd, result.string(), result.size()); + } else { + mHardwareLock.unlock(); + } + + bool locked = tryLock(mLock); + + // failed to lock - AudioFlinger is probably deadlocked + if (!locked) { + String8 result(kDeadlockedString); + write(fd, result.string(), result.size()); } dumpClients(fd, args); @@ -496,6 +514,14 @@ status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask) } LOGV("setOutput done\n"); } + // setRouting() is always called at least for mode == AudioSystem::MODE_IN_CALL when + // SCO is enabled, whatever current mode is so we can safely handle A2DP disabling only + // in this case to avoid doing it several times. + if (mode == AudioSystem::MODE_IN_CALL && + (mask & AudioSystem::ROUTE_BLUETOOTH_SCO)) { + AutoMutex lock(&mLock); + handleRouteDisablesA2dp_l(routes); + } #endif // do nothing if only A2DP routing is affected @@ -657,7 +683,7 @@ status_t AudioFlinger::setStreamMute(int stream, bool muted) if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return BAD_VALUE; } - + #ifdef WITH_A2DP mA2dpMixerThread->setStreamMute(stream, muted); #endif @@ -672,8 +698,6 @@ status_t AudioFlinger::setStreamMute(int stream, bool muted) mHardwareMixerThread->setStreamMute(stream, muted); } - - return NO_ERROR; } @@ -837,36 +861,29 @@ void AudioFlinger::handleForcedSpeakerRoute(int command) } #ifdef WITH_A2DP -// handleStreamDisablesA2dp_l() must be called with AudioFlinger::mLock held -void AudioFlinger::handleStreamDisablesA2dp_l(int command) +// handleRouteDisablesA2dp_l() must be called with AudioFlinger::mLock held +void AudioFlinger::handleRouteDisablesA2dp_l(int routes) { - switch(command) { - case ACTIVE_TRACK_ADDED: - { - if (mA2dpDisableCount++ == 0) { - if (mA2dpEnabled) { - setA2dpEnabled_l(false); - mA2dpSuppressed = true; - } - } - LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount); - } - break; - case ACTIVE_TRACK_REMOVED: - { - if (mA2dpDisableCount > 0) { - if (--mA2dpDisableCount == 0) { - if (mA2dpSuppressed) { - setA2dpEnabled_l(true); - mA2dpSuppressed = false; - } - } - LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount); - } else { - LOGE("mA2dpDisableCount is already zero"); + if (routes & AudioSystem::ROUTE_BLUETOOTH_SCO) { + if (mA2dpDisableCount++ == 0) { + if (mA2dpEnabled) { + setA2dpEnabled_l(false); + mA2dpSuppressed = true; } } - break; + LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount); + } else { + if (mA2dpDisableCount > 0) { + if (--mA2dpDisableCount == 0) { + if (mA2dpSuppressed) { + setA2dpEnabled_l(true); + mA2dpSuppressed = false; + } + } + LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount); + } else { + LOGE("mA2dpDisableCount is already zero"); + } } } #endif @@ -1500,13 +1517,6 @@ void AudioFlinger::MixerThread::addActiveTrack_l(const wp& t) if (streamForcedToSpeaker(track->type())) { mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED); } -#ifdef WITH_A2DP - // AudioFlinger::mLock must be locked before calling - // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l(). - if (streamDisablesA2dp(track->type())) { - mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED); - } -#endif } } @@ -1524,13 +1534,6 @@ void AudioFlinger::MixerThread::removeActiveTrack_l(const wp& t) if (streamForcedToSpeaker(track->type())) { mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED); } -#ifdef WITH_A2DP - // AudioFlinger::mLock must be locked before calling - // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l(). - if (streamDisablesA2dp(track->type())) { - mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED); - } -#endif } } @@ -1598,8 +1601,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( new(mCblk) audio_track_cblk_t(); // clear all buffers mCblk->frameCount = frameCount; - mCblk->sampleRate = sampleRate; - mCblk->channels = channelCount; + mCblk->sampleRate = (uint16_t)sampleRate; + mCblk->channels = (uint16_t)channelCount; if (sharedBuffer == 0) { mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); @@ -1622,8 +1625,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( new(mCblk) audio_track_cblk_t(); // clear all buffers mCblk->frameCount = frameCount; - mCblk->sampleRate = sampleRate; - mCblk->channels = channelCount; + mCblk->sampleRate = (uint16_t)sampleRate; + mCblk->channels = (uint16_t)channelCount; mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); // Force underrun condition to avoid false underrun callback until first data is @@ -1680,7 +1683,7 @@ sp AudioFlinger::MixerThread::TrackBase::getCblk() const } int AudioFlinger::MixerThread::TrackBase::sampleRate() const { - return mCblk->sampleRate; + return (int)mCblk->sampleRate; } int AudioFlinger::MixerThread::TrackBase::channelCount() const { @@ -1693,11 +1696,12 @@ void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t int16_t *bufferEnd = bufferStart + frames * cblk->channels; // Check validity of returned pointer in case the track control block would have been corrupted. - if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) { - LOGW("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ - server %d, serverBase %d, user %d, userBase %d", + if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd || + cblk->channels == 2 && ((unsigned long)bufferStart & 3) ) { + LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ + server %d, serverBase %d, user %d, userBase %d, channels %d", bufferStart, bufferEnd, mBuffer, mBufferEnd, - cblk->server, cblk->serverBase, cblk->user, cblk->userBase); + cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channels); return 0; } @@ -1864,12 +1868,14 @@ void AudioFlinger::MixerThread::Track::flush() // STOPPED state mState = STOPPED; + mCblk->lock.lock(); // NOTE: reset() will reset cblk->user and cblk->server with // the risk that at the same time, the AudioMixer is trying to read // data. In this case, getNextBuffer() would return a NULL pointer // as audio buffer => the AudioMixer code MUST always test that pointer // returned by getNextBuffer() is not NULL! reset(); + mCblk->lock.unlock(); } void AudioFlinger::MixerThread::Track::reset() @@ -2478,19 +2484,6 @@ status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* record mRecordTrack = recordTrack; -#ifdef WITH_A2DP - { // scope for lock2 - - // AudioFlinger::mLock must be locked before calling - // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l(). - AutoMutex lock2(&mAudioFlinger->mLock); - - // Currently there is no way to detect if we are recording over SCO, - // so we disable A2DP during any recording. - mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED); - } -#endif - // signal thread to start LOGV("Signal record thread"); mWaitWorkCV.signal(); @@ -2503,18 +2496,6 @@ void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack LOGV("AudioRecordThread::stop"); AutoMutex lock(&mLock); if (mActive && (recordTrack == mRecordTrack.get())) { -#ifdef WITH_A2DP - { // scope for lock2 - - // AudioFlinger::mLock must be locked before calling - // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l(). - AutoMutex lock2(&mAudioFlinger->mLock); - - // Currently there is no way to detect if we are recording over SCO, - // so we disable A2DP during any recording. - mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED); - } -#endif mActive = false; mStopped.wait(mLock); } diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index ab15947f866db..db5cc7444ba3c 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -165,7 +165,6 @@ private: void checkA2dpEnabledChange_l(); #endif static bool streamForcedToSpeaker(int streamType); - static bool streamDisablesA2dp(int streamType); // Management of forced route to speaker for certain track types. enum force_speaker_command { @@ -176,7 +175,7 @@ private: }; void handleForcedSpeakerRoute(int command); #ifdef WITH_A2DP - void handleStreamDisablesA2dp_l(int command); + void handleRouteDisablesA2dp_l(int routes); #endif // Internal dump utilites. diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp index b03467f6ced23..b02efcceb681e 100644 --- a/libs/audioflinger/AudioMixer.cpp +++ b/libs/audioflinger/AudioMixer.cpp @@ -16,6 +16,7 @@ */ #define LOG_TAG "AudioMixer" +//#define LOG_NDEBUG 0 #include #include @@ -780,8 +781,10 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* // in == NULL can happen if the track was flushed just after having // been enabled for mixing. - if (in == NULL) { + if (in == NULL || ((unsigned long)in & 3)) { memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t)); + LOGE_IF(((unsigned long)in & 3), "process stereo track: input buffer alignment pb: buffer %p track %d, channels %d, needs %08x", + in, i, t.channelCount, t.needs); return; } size_t outFrames = b.frameCount; diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java index 6672e299fe797..887574a66bad1 100644 --- a/location/java/com/android/internal/location/GpsLocationProvider.java +++ b/location/java/com/android/internal/location/GpsLocationProvider.java @@ -16,8 +16,10 @@ package com.android.internal.location; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.location.Criteria; import android.location.IGpsStatusListener; import android.location.Location; @@ -32,9 +34,14 @@ import android.os.SystemClock; import android.util.Config; import android.util.Log; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyIntents; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Properties; @@ -78,6 +85,11 @@ public class GpsLocationProvider extends LocationProviderImpl { */ public static final String EXTRA_ENABLED = "enabled"; + // these need to match GpsPositionMode enum in gps.h + private static final int GPS_POSITION_MODE_STANDALONE = 0; + private static final int GPS_POSITION_MODE_MS_BASED = 1; + private static final int GPS_POSITION_MODE_MS_ASSISTED = 2; + // these need to match GpsStatusValue defines in gps.h private static final int GPS_STATUS_NONE = 0; private static final int GPS_STATUS_SESSION_BEGIN = 1; @@ -135,6 +147,8 @@ public class GpsLocationProvider extends LocationProviderImpl { // requested frequency of fixes, in seconds private int mFixInterval = 1; + private int mPositionMode = GPS_POSITION_MODE_STANDALONE; + // true if we started navigation private boolean mStarted; @@ -156,7 +170,11 @@ public class GpsLocationProvider extends LocationProviderImpl { private GpsEventThread mEventThread; private GpsNetworkThread mNetworkThread; private Object mNetworkThreadLock = new Object(); - + + private String mSuplHost; + private int mSuplPort; + private boolean mSetSuplServer; + // how often to request NTP time, in milliseconds // current setting 4 hours private static final long NTP_INTERVAL = 4*60*60*1000; @@ -166,6 +184,27 @@ public class GpsLocationProvider extends LocationProviderImpl { private ILocationCollector mCollector; + private class TelephonyBroadcastReceiver extends BroadcastReceiver { + @Override public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { + String state = intent.getStringExtra(Phone.STATE_KEY); + String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); + String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); + + if (Config.LOGD) { + Log.d(TAG, "state: " + state + " apnName: " + apnName + " reason: " + reason); + } + if ("CONNECTED".equals(state)) { + native_set_supl_apn(apnName); + } else { + native_set_supl_apn(""); + } + } + } + } + public static boolean isSupported() { return native_is_supported(); } @@ -174,6 +213,11 @@ public class GpsLocationProvider extends LocationProviderImpl { super(LocationManager.GPS_PROVIDER); mContext = context; + TelephonyBroadcastReceiver receiver = new TelephonyBroadcastReceiver(); + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); + context.registerReceiver(receiver, intentFilter); + mProperties = new Properties(); try { File file = new File(PROPERTIES_FILE); @@ -181,6 +225,16 @@ public class GpsLocationProvider extends LocationProviderImpl { mProperties.load(stream); stream.close(); mNtpServer = mProperties.getProperty("NTP_SERVER", null); + mSuplHost = mProperties.getProperty("SUPL_HOST"); + String suplPortString = mProperties.getProperty("SUPL_PORT"); + if (mSuplHost != null && suplPortString != null) { + try { + mSuplPort = Integer.parseInt(suplPortString); + mSetSuplServer = true; + } catch (NumberFormatException e) { + Log.e(TAG, "unable to parse SUPL_PORT: " + suplPortString); + } + } } catch (IOException e) { Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE); } @@ -198,7 +252,7 @@ public class GpsLocationProvider extends LocationProviderImpl { public boolean requiresNetwork() { // We want updateNetworkState() to get called when the network state changes // for XTRA and NTP time injection support. - return (mNtpServer != null || native_supports_xtra()); + return (mNtpServer != null || native_supports_xtra() || mSuplHost != null); } public void updateNetworkState(int state) { @@ -542,7 +596,7 @@ public class GpsLocationProvider extends LocationProviderImpl { if (!mStarted) { if (Config.LOGV) Log.v(TAG, "startNavigating"); mStarted = true; - if (!native_start(false, mFixInterval)) { + if (!native_start(mPositionMode, false, mFixInterval)) { mStarted = false; Log.e(TAG, "native_start failed in startNavigating()"); } @@ -806,7 +860,7 @@ public class GpsLocationProvider extends LocationProviderImpl { } } waitTime = getWaitTime(); - } while (!mDone && ((!mXtraDownloadRequested && waitTime > 0) + } while (!mDone && ((!mXtraDownloadRequested && !mSetSuplServer && waitTime > 0) || !mNetworkAvailable)); if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop"); @@ -833,6 +887,29 @@ public class GpsLocationProvider extends LocationProviderImpl { } } + // Set the SUPL server address if we have not yet + if (mSetSuplServer) { + try { + InetAddress inetAddress = InetAddress.getByName(mSuplHost); + if (inetAddress != null) { + byte[] addrBytes = inetAddress.getAddress(); + long addr = 0; + for (int i = 0; i < addrBytes.length; i++) { + int temp = addrBytes[i]; + // signed -> unsigned + if (temp < 0) temp = 256 + temp; + addr = addr * 256 + temp; + } + // use MS-Based position mode if SUPL support is enabled + mPositionMode = GPS_POSITION_MODE_MS_BASED; + native_set_supl_server((int)addr, mSuplPort); + mSetSuplServer = false; + } + } catch (UnknownHostException e) { + Log.e(TAG, "unknown host for SUPL server " + mSuplHost); + } + } + if ((mXtraDownloadRequested || (mNextXtraTime > 0 && mNextXtraTime <= System.currentTimeMillis())) && xtraDownloader != null) { @@ -908,7 +985,7 @@ public class GpsLocationProvider extends LocationProviderImpl { private native boolean native_init(); private native void native_disable(); private native void native_cleanup(); - private native boolean native_start(boolean singleFix, int fixInterval); + private native boolean native_start(int positionMode, boolean singleFix, int fixInterval); private native boolean native_stop(); private native void native_set_fix_frequency(int fixFrequency); private native void native_delete_aiding_data(int flags); @@ -922,4 +999,8 @@ public class GpsLocationProvider extends LocationProviderImpl { private native void native_inject_time(long time, long timeReference, int uncertainty); private native boolean native_supports_xtra(); private native void native_inject_xtra_data(byte[] data, int length); + + // SUPL Support + private native void native_set_supl_server(int addr, int port); + private native void native_set_supl_apn(String apn); } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 077d016433af7..f509fb5abf267 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -160,7 +160,7 @@ public class AudioManager { 16, // STREAM_MUSIC 8, // STREAM_ALARM 8, // STREAM_NOTIFICATION - 15, // STREAM_BLUETOOTH_SCO + 16, // STREAM_BLUETOOTH_SCO }; /** @hide Default volume index values for audio streams */ @@ -220,7 +220,7 @@ public class AudioManager { * By default this is on for the ring stream. If this flag is included, * this behavior will be present regardless of the stream type being * affected by the ringer mode. - * + * * @see #adjustVolume(int, int) * @see #adjustStreamVolume(int, int, int) */ @@ -954,25 +954,21 @@ public class AudioManager { /** * IME standard keypress sound * @see #playSoundEffect(int) - * @hide FIXME: Unhide before release */ public static final int FX_KEYPRESS_STANDARD = 5; /** * IME spacebar keypress sound * @see #playSoundEffect(int) - * @hide FIXME: Unhide before release */ public static final int FX_KEYPRESS_SPACEBAR = 6; /** * IME delete keypress sound * @see #playSoundEffect(int) - * @hide FIXME: Unhide before release */ public static final int FX_KEYPRESS_DELETE = 7; /** * IME return_keypress sound * @see #playSoundEffect(int) - * @hide FIXME: Unhide before release */ public static final int FX_KEYPRESS_RETURN = 8; /** @@ -988,11 +984,10 @@ public class AudioManager { * {@link #FX_FOCUS_NAVIGATION_DOWN}, * {@link #FX_FOCUS_NAVIGATION_LEFT}, * {@link #FX_FOCUS_NAVIGATION_RIGHT}, - * FIXME: include links before release - * {link #FX_KEYPRESS_STANDARD}, - * {link #FX_KEYPRESS_SPACEBAR}, - * {link #FX_KEYPRESS_DELETE}, - * {link #FX_KEYPRESS_RETURN}, + * {@link #FX_KEYPRESS_STANDARD}, + * {@link #FX_KEYPRESS_SPACEBAR}, + * {@link #FX_KEYPRESS_DELETE}, + * {@link #FX_KEYPRESS_RETURN}, * NOTE: This version uses the UI settings to determine * whether sounds are heard or not. */ @@ -1021,15 +1016,13 @@ public class AudioManager { * {@link #FX_FOCUS_NAVIGATION_DOWN}, * {@link #FX_FOCUS_NAVIGATION_LEFT}, * {@link #FX_FOCUS_NAVIGATION_RIGHT}, - * FIXME: include links before release - * {link #FX_KEYPRESS_STANDARD}, - * {link #FX_KEYPRESS_SPACEBAR}, - * {link #FX_KEYPRESS_DELETE}, - * {link #FX_KEYPRESS_RETURN}, + * {@link #FX_KEYPRESS_STANDARD}, + * {@link #FX_KEYPRESS_SPACEBAR}, + * {@link #FX_KEYPRESS_DELETE}, + * {@link #FX_KEYPRESS_RETURN}, * @param volume Sound effect volume * NOTE: This version is for applications that have their own * settings panel for enabling and controlling volume. - * @hide FIXME: Unhide before release */ public void playSoundEffect(int effectType, float volume) { if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 316fa7a5f92ee..d2bad93f95454 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -170,6 +170,10 @@ public class AudioTrack * Handler for marker events coming from the native code */ private NativeEventHandlerDelegate mEventHandlerDelegate = null; + /** + * Looper associated with the thread that creates the AudioTrack instance + */ + private Looper mInitializationLooper = null; /** * The audio data sampling rate in Hz. */ @@ -248,6 +252,11 @@ public class AudioTrack int bufferSizeInBytes, int mode) throws IllegalArgumentException { mState = STATE_UNINITIALIZED; + + // remember which looper is associated with the AudioTrack instanciation + if ((mInitializationLooper = Looper.myLooper()) == null) { + mInitializationLooper = Looper.getMainLooper(); + } audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode); @@ -902,11 +911,10 @@ public class AudioTrack if (handler != null) { looper = handler.getLooper(); } else { - // no given handler, look for main looper - if ((looper = Looper.myLooper()) == null) { - looper = Looper.getMainLooper(); - } + // no given handler, use the looper the AudioTrack was created in + looper = mInitializationLooper; } + // construct the event handler with this looper if (looper != null) { // implement the event handler delegate diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java index 9de0eec463c61..6539d8467d7b3 100644 --- a/media/java/android/media/JetPlayer.java +++ b/media/java/android/media/JetPlayer.java @@ -68,21 +68,22 @@ public class JetPlayer //-------------------------------------------- // Member variables //------------------------ - private EventHandler mNativeEventHandler = null; + /** + * Handler for jet events and status updates coming from the native code + */ + private NativeEventHandler mEventHandler = null; /** - * Lock to protect status listener updates against status change notifications + * Looper associated with the thread that creates the AudioTrack instance */ - private final Object mStatusListenerLock = new Object(); + private Looper mInitializationLooper = null; /** * Lock to protect the event listener updates against event notifications */ private final Object mEventListenerLock = new Object(); - private JetStatusUpdateListener mJetStatusUpdateListener = null; - - private JetEventListener mJetEventListener = null; + private OnJetEventListener mJetEventListener = null; private static JetPlayer singletonRef; @@ -115,6 +116,11 @@ public class JetPlayer private JetPlayer() { + + // remember which looper is associated with the JetPlayer instanciation + if ((mInitializationLooper = Looper.myLooper()) == null) { + mInitializationLooper = Looper.getMainLooper(); + } native_setup(new WeakReference(this), JetPlayer.getMaxTracks(), @@ -132,18 +138,6 @@ public class JetPlayer } - private void createNativeEventHandler() { - Looper looper; - if ((looper = Looper.myLooper()) != null) { - mNativeEventHandler = new EventHandler(this, looper); - } else if ((looper = Looper.getMainLooper()) != null) { - mNativeEventHandler = new EventHandler(this, looper); - } else { - mNativeEventHandler = null; - } - } - - //-------------------------------------------- // Getters //------------------------ @@ -235,24 +229,27 @@ public class JetPlayer //--------------------------------------------------------- // Internal class to handle events posted from native code //------------------------ - private class EventHandler extends Handler + private class NativeEventHandler extends Handler { private JetPlayer mJet; - public EventHandler(JetPlayer jet, Looper looper) { + public NativeEventHandler(JetPlayer jet, Looper looper) { super(looper); mJet = jet; } @Override public void handleMessage(Message msg) { + OnJetEventListener listener = null; + synchronized (mEventListenerLock) { + listener = mJet.mJetEventListener; + } switch(msg.what) { case JET_EVENT: - synchronized (mEventListenerLock) { - if (mJetEventListener != null) { - // call the appropriate listener after decoding the event parameters - // encoded in msg.arg1 - mJetEventListener.onJetEvent( + if (listener != null) { + // call the appropriate listener after decoding the event parameters + // encoded in msg.arg1 + mJetEventListener.onJetEvent( mJet, (short)((msg.arg1 & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT), (byte) ((msg.arg1 & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT), @@ -261,28 +258,21 @@ public class JetPlayer (byte)(((msg.arg1 & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT) + 1), (byte) ((msg.arg1 & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT), (byte) (msg.arg1 & JET_EVENT_VAL_MASK) ); - } } return; case JET_USERID_UPDATE: - synchronized (mStatusListenerLock) { - if (mJetStatusUpdateListener != null) { - mJetStatusUpdateListener.onJetUserIdUpdate(mJet, msg.arg1, msg.arg2); - } + if (listener != null) { + listener.onJetUserIdUpdate(mJet, msg.arg1, msg.arg2); } return; case JET_NUMQUEUEDSEGMENT_UPDATE: - synchronized (mStatusListenerLock) { - if (mJetStatusUpdateListener != null) { - mJetStatusUpdateListener.onJetNumQueuedSegmentUpdate(mJet, msg.arg1); - } + if (listener != null) { + listener.onJetNumQueuedSegmentUpdate(mJet, msg.arg1); } return; case JET_PAUSE_UPDATE: - synchronized (mStatusListenerLock) { - if (mJetStatusUpdateListener != null) - mJetStatusUpdateListener.onJetPauseUpdate(mJet, msg.arg1); - } + if (listener != null) + listener.onJetPauseUpdate(mJet, msg.arg1); return; default: @@ -294,22 +284,48 @@ public class JetPlayer //-------------------------------------------- - // Jet status update listener + // Jet event listener //------------------------ - public void setStatusUpdateListener(JetStatusUpdateListener listener) { - synchronized(mStatusListenerLock) { - mJetStatusUpdateListener = listener; - } - - if ((listener != null) && (mNativeEventHandler == null)) { - createNativeEventHandler(); + public void setEventListener(OnJetEventListener listener) { + setEventListener(listener, null); + } + + public void setEventListener(OnJetEventListener listener, Handler handler) { + synchronized(mEventListenerLock) { + + mJetEventListener = listener; + + if (listener != null) { + if (handler != null) { + mEventHandler = new NativeEventHandler(this, handler.getLooper()); + } else { + // no given handler, use the looper the AudioTrack was created in + mEventHandler = new NativeEventHandler(this, mInitializationLooper); + } + } else { + mEventHandler = null; + } + } } + /** - * Handles the notification when the JET status is updated. + * Handles the notification when the JET engine generates an event. */ - public interface JetStatusUpdateListener { + public interface OnJetEventListener { + /** + * Callback for when the JET engine generates a new event. + * + * @param player the JET player the event is coming from + * @param segment 8 bit unsigned value + * @param track 6 bit unsigned value + * @param channel 4 bit unsigned value + * @param controller 7 bit unsigned value + * @param value 7 bit unsigned value + */ + void onJetEvent(JetPlayer player, + short segment, byte track, byte channel, byte controller, byte value); /** * Callback for when JET's currently playing segment userID is updated. * @@ -337,38 +353,6 @@ public class JetPlayer } - //-------------------------------------------- - // Jet event listener - //------------------------ - public void setEventListener(JetEventListener listener) { - synchronized(mEventListenerLock) { - mJetEventListener = listener; - } - - if ((listener != null) && (mNativeEventHandler == null)) { - createNativeEventHandler(); - } - } - - /** - * Handles the notification when the JET engine generates an event. - */ - public interface JetEventListener { - /** - * Callback for when the JET engine generates a new event. - * - * @param player the JET player the event is coming from - * @param segment 8 bit unsigned value - * @param track 6 bit unsigned value - * @param channel 4 bit unsigned value - * @param controller 7 bit unsigned value - * @param value 7 bit unsigned value - */ - void onJetEvent(JetPlayer player, - short segment, byte track, byte channel, byte controller, byte value); - } - - //-------------------------------------------- // Native methods //------------------------ @@ -397,13 +381,15 @@ public class JetPlayer @SuppressWarnings("unused") private static void postEventFromNative(Object jetplayer_ref, int what, int arg1, int arg2) { - + //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2); JetPlayer jet = (JetPlayer)((WeakReference)jetplayer_ref).get(); - if( (jet!=null) && (jet.mNativeEventHandler!=null) ){ - Message m = jet.mNativeEventHandler.obtainMessage(what, arg1, arg2, null); - jet.mNativeEventHandler.sendMessage(m); + if ((jet != null) && (jet.mEventHandler != null)) { + Message m = + jet.mEventHandler.obtainMessage(what, arg1, arg2, null); + jet.mEventHandler.sendMessage(m); } + } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 202d0ae931fe6..9668efac87100 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1036,11 +1036,11 @@ public class MediaPlayer * Register a callback to be invoked when the media source is ready * for playback. * - * @param l the callback that will be run + * @param listener the callback that will be run */ - public void setOnPreparedListener(OnPreparedListener l) + public void setOnPreparedListener(OnPreparedListener listener) { - mOnPreparedListener = l; + mOnPreparedListener = listener; } private OnPreparedListener mOnPreparedListener; @@ -1063,11 +1063,11 @@ public class MediaPlayer * Register a callback to be invoked when the end of a media source * has been reached during playback. * - * @param l the callback that will be run + * @param listener the callback that will be run */ - public void setOnCompletionListener(OnCompletionListener l) + public void setOnCompletionListener(OnCompletionListener listener) { - mOnCompletionListener = l; + mOnCompletionListener = listener; } private OnCompletionListener mOnCompletionListener; @@ -1092,11 +1092,11 @@ public class MediaPlayer * Register a callback to be invoked when the status of a network * stream's buffer has changed. * - * @param l the callback that will be run + * @param listener the callback that will be run. */ - public void setOnBufferingUpdateListener(OnBufferingUpdateListener l) + public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener) { - mOnBufferingUpdateListener = l; + mOnBufferingUpdateListener = listener; } private OnBufferingUpdateListener mOnBufferingUpdateListener; @@ -1119,11 +1119,11 @@ public class MediaPlayer * Register a callback to be invoked when a seek operation has been * completed. * - * @param l the callback that will be run + * @param listener the callback that will be run */ - public void setOnSeekCompleteListener(OnSeekCompleteListener l) + public void setOnSeekCompleteListener(OnSeekCompleteListener listener) { - mOnSeekCompleteListener = l; + mOnSeekCompleteListener = listener; } private OnSeekCompleteListener mOnSeekCompleteListener; @@ -1151,12 +1151,12 @@ public class MediaPlayer * Register a callback to be invoked when the video size is * known or updated. * - * @param l the callback that will be run + * @param listener the callback that will be run * @hide */ - public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener l) + public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener) { - mOnVideoSizeChangedListener = l; + mOnVideoSizeChangedListener = listener; } private OnVideoSizeChangedListener mOnVideoSizeChangedListener; diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 1c08cba5d4491..676f24166dbc5 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -259,12 +259,33 @@ public class MediaRecorder /** * Sets the maximum duration (in ms) of the recording session. * Call this after setOutFormat() but before prepare(). + * After recording reaches the specified duration, a notification + * will be sent to the {@link android.media.MediaRecorder.OnInfoListener} + * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED} + * and recording will be stopped. Stopping happens asynchronously, there + * is no guarantee that the recorder will have stopped by the time the + * listener is notified. * * @param max_duration_ms the maximum duration in ms (if zero or negative, disables the duration limit) * */ public native void setMaxDuration(int max_duration_ms) throws IllegalArgumentException; + /** + * Sets the maximum filesize (in bytes) of the recording session. + * Call this after setOutFormat() but before prepare(). + * After recording reaches the specified filesize, a notification + * will be sent to the {@link android.media.MediaRecorder.OnInfoListener} + * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED} + * and recording will be stopped. Stopping happens asynchronously, there + * is no guarantee that the recorder will have stopped by the time the + * listener is notified. + * + * @param max_filesize_bytes the maximum filesize in bytes (if zero or negative, disables the limit) + * + */ + public native void setMaxFileSize(long max_filesize_bytes) throws IllegalArgumentException; + /** * Sets the audio encoder to be used for recording. If this method is not * called, the output file will not contain an audio track. Call this after @@ -441,6 +462,10 @@ public class MediaRecorder * @see android.media.MediaRecorder.OnInfoListener */ public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; + /** A maximum filesize had been setup and has now been reached. + * @see android.media.MediaRecorder.OnInfoListener + */ + public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801; /** * Interface definition for a callback to be invoked when an error @@ -455,6 +480,8 @@ public class MediaRecorder * @param what the type of error that has occurred: *
    *
  • {@link #MEDIA_RECORDER_INFO_UNKNOWN} + *
  • {@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED} + *
  • {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED} *
* @param extra an extra code, specific to the error type */ diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 1e508d29e27a3..209b09f7c2e7f 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -267,6 +267,19 @@ android_media_MediaRecorder_setMaxDuration(JNIEnv *env, jobject thiz, jint max_d process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxDuration failed."); } +static void +android_media_MediaRecorder_setMaxFileSize( + JNIEnv *env, jobject thiz, jlong max_filesize_bytes) +{ + LOGV("setMaxFileSize(%lld)", max_filesize_bytes); + sp mr = getMediaRecorder(env, thiz); + + char params[64]; + sprintf(params, "max-filesize=%lld", max_filesize_bytes); + + process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxFileSize failed."); +} + static void android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz) { @@ -370,6 +383,7 @@ static JNINativeMethod gMethods[] = { {"setVideoSize", "(II)V", (void *)android_media_MediaRecorder_setVideoSize}, {"setVideoFrameRate", "(I)V", (void *)android_media_MediaRecorder_setVideoFrameRate}, {"setMaxDuration", "(I)V", (void *)android_media_MediaRecorder_setMaxDuration}, + {"setMaxFileSize", "(J)V", (void *)android_media_MediaRecorder_setMaxFileSize}, {"_prepare", "()V", (void *)android_media_MediaRecorder_prepare}, {"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude}, {"start", "()V", (void *)android_media_MediaRecorder_start}, diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index d26b0c578052a..7537ddf9bb322 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -387,12 +387,10 @@ void AudioTrack::flush() LOGV("flush"); if (!mActive) { - mCblk->lock.lock(); mAudioTrack->flush(); // Release AudioTrack callback thread in case it was waiting for new buffers // in AudioTrack::obtainBuffer() mCblk->cv.signal(); - mCblk->lock.unlock(); } } @@ -443,7 +441,7 @@ void AudioTrack::setSampleRate(int rate) if (rate > afSamplingRate*2) rate = afSamplingRate*2; if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE; - mCblk->sampleRate = rate; + mCblk->sampleRate = (uint16_t)rate; } uint32_t AudioTrack::getSampleRate() diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp index 2c6210471d3a2..77a901326592d 100644 --- a/media/libmedia/JetPlayer.cpp +++ b/media/libmedia/JetPlayer.cpp @@ -194,8 +194,15 @@ int JetPlayer::render() { } while (1) { + mMutex.lock(); // [[[[[[[[ LOCK --------------------------------------- + if (mEasData == NULL) { + mMutex.unlock(); + LOGV("JetPlayer::render(): NULL EAS data, exiting render."); + goto threadExit; + } + // nothing to render, wait for client thread to wake us up while (!mRender) { @@ -255,7 +262,10 @@ int JetPlayer::render() { }//while (1) threadExit: - mAudioTrack->flush(); + if (mAudioTrack) { + mAudioTrack->stop(); + mAudioTrack->flush(); + } if (mAudioBuffer) { delete [] mAudioBuffer; mAudioBuffer = NULL; diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp index 23b3b9d2d29b0..6b26faf736135 100644 --- a/media/libmedia/mediarecorder.cpp +++ b/media/libmedia/mediarecorder.cpp @@ -367,8 +367,9 @@ status_t MediaRecorder::setParameters(const String8& params) { status_t ret = mMediaRecorder->setParameters(params); if (OK != ret) { LOGE("setParameters(%s) failed: %d", params.string(), ret); - mCurrentState = MEDIA_RECORDER_ERROR; - return ret; + // Do not change our current state to MEDIA_RECORDER_ERROR, failures + // of the only currently supported parameters, "max-duration" and + // "max-filesize" are _not_ fatal. } return ret; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java index 3c449c90530b5..6edc2cc0d61b6 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java @@ -16,12 +16,13 @@ package com.android.mediaframeworktest; -import com.android.mediaframeworktest.functional.MediaPlayerApiTest; -import com.android.mediaframeworktest.functional.SimTonesTest; -import com.android.mediaframeworktest.functional.MediaMetadataTest; import com.android.mediaframeworktest.functional.CameraTest; -import com.android.mediaframeworktest.functional.MediaRecorderTest; import com.android.mediaframeworktest.functional.MediaAudioTrackTest; +import com.android.mediaframeworktest.functional.MediaMetadataTest; +import com.android.mediaframeworktest.functional.MediaMimeTest; +import com.android.mediaframeworktest.functional.MediaPlayerApiTest; +import com.android.mediaframeworktest.functional.MediaRecorderTest; +import com.android.mediaframeworktest.functional.SimTonesTest; import junit.framework.TestSuite; @@ -50,6 +51,7 @@ public class MediaFrameworkTestRunner extends InstrumentationTestRunner { suite.addTestSuite(CameraTest.class); suite.addTestSuite(MediaRecorderTest.class); suite.addTestSuite(MediaAudioTrackTest.class); + suite.addTestSuite(MediaMimeTest.class); return suite; } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java new file mode 100644 index 0000000000000..d2809c1a4beaa --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2009 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.mediaframeworktest.functional; + +import java.io.File; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; +import com.android.mediaframeworktest.MediaFrameworkTest; + +/* + * System tests for the handling of mime type in the media framework. + * + * To run this test suite: + make frameworks/base/media/tests/MediaFrameworkTest + make mediaframeworktest + + adb install -r out/target/product/dream/data/app/mediaframeworktest.apk + + adb shell am instrument -e class \ + com.android.mediaframeworktest.functional.MediaMimeTest \ + -w com.android.mediaframeworktest/.MediaFrameworkTestRunner + * + */ +public class MediaMimeTest extends ActivityInstrumentationTestCase2 { + private final String TAG = "MediaMimeTest"; + private Context mContext; + private final String MP3_FILE = "/sdcard/media_api/music/SHORTMP3.mp3"; + private final String MEDIA_PLAYBACK_NAME = "com.android.music.MediaPlaybackActivity"; + + public MediaMimeTest() { + super("com.android.mediaframeworktest", MediaFrameworkTest.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mContext = getActivity(); + // Checks you have all the test files on your SDCARD. + assertTrue(new File(MP3_FILE).exists()); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + // ---------------------------------------------------------------------- + // AUDIO mime type resolution tests. + + @MediumTest + // Checks the MediaPlaybackActivity handles audio/mp3. + public void testCheckMediaPlaybackHandlesAudioMp3() throws Exception { + assertMediaPlaybackActivityHandles("audio/mp3"); + } + + @MediumTest + // Checks the MediaPlaybackActivity handles audio/*. + public void testCheckMediaPlaybackHandlesAudio() throws Exception { + assertMediaPlaybackActivityHandles("audio/*"); + } + + @MediumTest + // Checks the MediaPlaybackActivity handles application/itunes. Some servers + // set the Content-type header to application/iTunes (with capital T, but + // the download manager downcasts it) for their MP3 podcasts. This is non + // standard but we try to support it anyway. + // See bug 1401491 + public void testCheckMediaPlaybackHandlesApplicationItunes() throws Exception { + assertMediaPlaybackActivityHandles("application/itunes"); + } + + @MediumTest + // Checks the activity resolver handling of mime types is case sensitive. + // See bug 1710534 + public void testCheckActivityResolverMimeHandlingIsCaseSensitive() throws Exception { + assertNoActivityHandles("AUDIO/MP3"); // <--- look uppercase + } + + @MediumTest + // Checks the activity resolver does not trims leading whitespaces when + // resolving mime types. Trailing whitespaces seems to be non + // significant. + // See bug 1710534 + public void testCheckWhiteSpacesInMimeTypeHandling() throws Exception { + assertNoActivityHandles(" audio/mp3"); + assertNoActivityHandles(" audio/mp3 "); + assertMediaPlaybackActivityHandles("audio/mp3 "); + } + + // @return a ResolveInfo instance for the mime type or null if the type is + // not handled by any activity. + private ResolveInfo resolveMime(String mime) { + Intent viewIntent = new Intent(Intent.ACTION_VIEW); + Uri uri = Uri.fromParts("file", MP3_FILE, null); + + viewIntent.setDataAndType(uri, mime); + return mContext.getPackageManager().resolveActivity( + viewIntent, PackageManager.MATCH_DEFAULT_ONLY); + } + + // Helper method to check the media playback activity handles the given mime type. + // @param mime type to test for + private void assertMediaPlaybackActivityHandles(String mime) throws Exception { + ResolveInfo ri = resolveMime(mime); + + assertNotNull(ri); + assertEquals(MEDIA_PLAYBACK_NAME, ri.activityInfo.name.toString()); + } + + // Helper method to check that NO activity handles the given mime type. + // @param mime type to test for + private void assertNoActivityHandles(String mime) throws Exception { + assertNull(resolveMime(mime)); + } +} diff --git a/packages/SettingsProvider/etc/Android.mk b/packages/SettingsProvider/etc/Android.mk index d73175f3d0955..81ca4b1c628b6 100644 --- a/packages/SettingsProvider/etc/Android.mk +++ b/packages/SettingsProvider/etc/Android.mk @@ -31,17 +31,3 @@ LOCAL_SRC_FILES := $(LOCAL_MODULE) include $(BUILD_PREBUILT) -######################## -include $(CLEAR_VARS) - -LOCAL_MODULE := favorites.xml - -LOCAL_MODULE_TAGS := user - -# This will install the file in /system/etc -# -LOCAL_MODULE_CLASS := ETC - -LOCAL_SRC_FILES := $(LOCAL_MODULE) - -include $(BUILD_PREBUILT) diff --git a/packages/SettingsProvider/etc/favorites.xml b/packages/SettingsProvider/etc/favorites.xml deleted file mode 100644 index ae74b8ee4750d..0000000000000 --- a/packages/SettingsProvider/etc/favorites.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java index 3a9a59f85be6a..73ff5016735ff 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -176,6 +176,9 @@ class BatteryService extends Binder { private synchronized final void update() { native_update(); + boolean logOutlier = false; + long dischargeDuration = 0; + mBatteryLevelCritical = mBatteryLevel <= CRITICAL_BATTERY_LEVEL; if (mAcOnline) { mPlugType = BatteryManager.BATTERY_PLUGGED_AC; @@ -199,13 +202,12 @@ class BatteryService extends Binder { // There's no value in this data unless we've discharged at least once and the // battery level has changed; so don't log until it does. if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryLevel) { - long duration = SystemClock.elapsedRealtime() - mDischargeStartTime; - EventLog.writeEvent(LOG_BATTERY_DISCHARGE_STATUS, duration, + dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; + logOutlier = true; + EventLog.writeEvent(LOG_BATTERY_DISCHARGE_STATUS, dischargeDuration, mDischargeStartLevel, mBatteryLevel); // make sure we see a discharge event before logging again mDischargeStartTime = 0; - - logOutlier(duration); } } else if (mPlugType == BATTERY_PLUGGED_NONE) { // charging -> discharging or we just powered up @@ -231,7 +233,8 @@ class BatteryService extends Binder { mPlugType == BATTERY_PLUGGED_NONE) { // We want to make sure we log discharge cycle outliers // if the battery is about to die. - logOutlier(SystemClock.elapsedRealtime() - mDischargeStartTime); + dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; + logOutlier = true; } mLastBatteryStatus = mBatteryStatus; @@ -244,6 +247,11 @@ class BatteryService extends Binder { mLastBatteryLevelCritical = mBatteryLevelCritical; sendIntent(); + + // This needs to be done after sendIntent() so that we get the lastest battery stats. + if (logOutlier && dischargeDuration != 0) { + logOutlier(dischargeDuration); + } } } @@ -252,7 +260,7 @@ class BatteryService extends Binder { Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); try { - mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE); + mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE, mBatteryLevel); } catch (RemoteException e) { // Should never happen. } diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java index 2131ffdd17c04..7466a376926f2 100755 --- a/services/java/com/android/server/HardwareService.java +++ b/services/java/com/android/server/HardwareService.java @@ -35,11 +35,23 @@ import android.util.Log; public class HardwareService extends IHardwareService.Stub { private static final String TAG = "HardwareService"; + static final int LIGHT_ID_BACKLIGHT = 0; + static final int LIGHT_ID_KEYBOARD = 1; + static final int LIGHT_ID_BUTTONS = 2; + static final int LIGHT_ID_BATTERY = 3; + static final int LIGHT_ID_NOTIFICATIONS = 4; + static final int LIGHT_ID_ATTENTION = 5; + + static final int LIGHT_FLASH_NONE = 0; + static final int LIGHT_FLASH_TIMED = 1; + HardwareService(Context context) { // Reset the hardware to a default state, in case this is a runtime // restart instead of a fresh boot. vibratorOff(); + mNativePointer = init_native(); + mContext = context; PowerManager pm = (PowerManager)context.getSystemService( Context.POWER_SERVICE); @@ -51,9 +63,18 @@ public class HardwareService extends IHardwareService.Stub { context.registerReceiver(mIntentReceiver, filter); } + protected void finalize() throws Throwable { + finalize_native(mNativePointer); + super.finalize(); + } + public void vibrate(long milliseconds) { - vibratePattern(new long[] { 0, milliseconds }, -1, - new Binder()); + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires VIBRATE permission"); + } + doCancelVibrate(); + vibratorOn(milliseconds); } private boolean isAll0(long[] pattern) { @@ -164,38 +185,40 @@ public class HardwareService extends IHardwareService.Stub { Hardware.enableCameraFlash(milliseconds); } - public void setScreenBacklight(int brightness) { + public void setBacklights(int brightness) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires HARDWARE_TEST permission"); } // Don't let applications turn the screen all the way off brightness = Math.max(brightness, Power.BRIGHTNESS_DIM); - Hardware.setScreenBacklight(brightness); + setLightBrightness_UNCHECKED(LIGHT_ID_BACKLIGHT, brightness); + setLightBrightness_UNCHECKED(LIGHT_ID_KEYBOARD, brightness); + setLightBrightness_UNCHECKED(LIGHT_ID_BUTTONS, brightness); } - public void setKeyboardBacklight(boolean on) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires HARDWARE_TEST permission"); - } - Hardware.setKeyboardBacklight(on); + void setLightOff_UNCHECKED(int light) { + setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0); } - public void setButtonBacklight(boolean on) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires HARDWARE_TEST permission"); - } - Hardware.setButtonBacklight(on); + void setLightBrightness_UNCHECKED(int light, int brightness) { + int b = brightness & 0x000000ff; + b = 0xff000000 | (b << 16) | (b << 8) | b; + setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0); } - public void setLedState(int colorARGB, int onMS, int offMS) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires HARDWARE_TEST permission"); - } - Hardware.setLedState(colorARGB, onMS, offMS); + void setLightColor_UNCHECKED(int light, int color) { + setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0); + } + + void setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS) { + setLight_native(mNativePointer, light, color, mode, onMS, offMS); + } + + public void setAttentionLight(boolean on) { + // Not worthy of a permission. We shouldn't have a flashlight permission. + setLight_native(mNativePointer, LIGHT_ID_ATTENTION, on ? 0xffffffff : 0, + LIGHT_FLASH_NONE, 0, 0); } private void doCancelVibrate() { @@ -206,8 +229,8 @@ public class HardwareService extends IHardwareService.Stub { mThread.notify(); } mThread = null; - vibratorOff(); } + vibratorOff(); } } @@ -315,6 +338,12 @@ public class HardwareService extends IHardwareService.Stub { } } }; + + private static native int init_native(); + private static native void finalize_native(int ptr); + + private static native void setLight_native(int ptr, int light, int color, int mode, + int onMS, int offMS); private Context mContext; private PowerManager.WakeLock mWakeLock; @@ -323,6 +352,8 @@ public class HardwareService extends IHardwareService.Stub { volatile Death mDeath; volatile IBinder mToken; + private int mNativePointer; + native static void vibratorOn(long milliseconds); native static void vibratorOff(); } diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java index 855734dcb80e5..c9066bedd96bd 100644 --- a/services/java/com/android/server/HeadsetObserver.java +++ b/services/java/com/android/server/HeadsetObserver.java @@ -98,12 +98,12 @@ class HeadsetObserver extends UEventObserver { sendIntent(isUnplug); if (isUnplug) { - // It often takes >200ms to flush the audio pipeline after apps - // pause audio playback, but audio route changes are immediate, - // so delay the route change by 400ms. + // It can take hundreds of ms flush the audio pipeline after + // apps pause audio playback, but audio route changes are + // immediate, so delay the route change by 1000ms. // This could be improved once the audio sub-system provides an // interface to clear the audio pipeline. - mHandler.sendEmptyMessageDelayed(0, 400); + mHandler.sendEmptyMessageDelayed(0, 1000); } else { updateAudioRoute(); } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 994832244f195..4198154184db5 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -308,6 +308,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mScreenOn = true; } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { mScreenOn = false; + } else if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { + hideInputMethodMenu(); + return; } else { Log.w(TAG, "Unexpected intent " + intent); } @@ -436,6 +439,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub IntentFilter screenOnOffFilt = new IntentFilter(); screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON); screenOnOffFilt.addAction(Intent.ACTION_SCREEN_OFF); + screenOnOffFilt.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt); buildInputMethodListLocked(mMethodList, mMethodMap); @@ -585,6 +589,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + mCurClient.pid + " uid " + mCurClient.uid); } mCurClient = null; + + hideInputMethodMenuLocked(); } } @@ -820,6 +826,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurToken = null; } + mCurId = null; clearCurMethodLocked(); if (reportToClient && mCurClient != null) { @@ -896,10 +903,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub setInputMethodLocked(id); } catch (IllegalArgumentException e) { Log.w(TAG, "Unknown input method from prefs: " + id, e); + mCurMethodId = null; unbindCurrentMethodLocked(true); } } else { // There is no longer an input method set, so stop any current one. + mCurMethodId = null; unbindCurrentMethodLocked(true); } } @@ -1436,18 +1445,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } void hideInputMethodMenu() { + synchronized (mMethodMap) { + hideInputMethodMenuLocked(); + } + } + + void hideInputMethodMenuLocked() { if (DEBUG) Log.v(TAG, "Hide switching menu"); - synchronized (mMethodMap) { - if (mSwitchingDialog != null) { - mSwitchingDialog.dismiss(); - mSwitchingDialog = null; - } - - mDialogBuilder = null; - mItems = null; - mIms = null; + if (mSwitchingDialog != null) { + mSwitchingDialog.dismiss(); + mSwitchingDialog = null; } + + mDialogBuilder = null; + mItems = null; + mIms = null; } // ---------------------------------------------------------------------- @@ -1584,7 +1597,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } p.println(" mInputMethodIcon=" + mInputMethodIcon); p.println(" mInputMethodData=" + mInputMethodData); - p.println(" mCurrentMethod=" + mCurMethodId); + p.println(" mCurMethodId=" + mCurMethodId); client = mCurClient; p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq); p.println(" mCurFocusedWindow=" + mCurFocusedWindow); diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java index 63b486ce77d78..411cd6bce1350 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -176,7 +176,7 @@ public abstract class KeyInputQueue { keycode, repeatCount, device != null ? device.mMetaKeysState : 0, device != null ? device.id : -1, scancode, - flags); + flags | KeyEvent.FLAG_FROM_SYSTEM); } Thread mThread = new Thread("InputDeviceReader") { diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index e48e04757826b..5abf249ca09de 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -86,6 +86,7 @@ import com.android.server.am.BatteryStatsService; public class LocationManagerService extends ILocationManager.Stub implements INetworkLocationManager { private static final String TAG = "LocationManagerService"; + private static final boolean LOCAL_LOGV = false; // Minimum time interval between last known location writes, in milliseconds. private static final long MIN_LAST_KNOWN_LOCATION_TIME = 60L * 1000L; @@ -338,8 +339,8 @@ public class LocationManagerService extends ILocationManager.Stub } public void binderDied() { - if (Config.LOGD) { - Log.d(TAG, "Location listener died"); + if (LOCAL_LOGV) { + Log.v(TAG, "Location listener died"); } synchronized (mLocationListeners) { removeUpdatesLocked(this); @@ -486,9 +487,9 @@ public class LocationManagerService extends ILocationManager.Stub String name = subdirs[i].getName(); - if (Config.LOGD) { - Log.d(TAG, "Found dir " + subdirs[i].getAbsolutePath()); - Log.d(TAG, "name = " + name); + if (LOCAL_LOGV) { + Log.v(TAG, "Found dir " + subdirs[i].getAbsolutePath()); + Log.v(TAG, "name = " + name); } // Don't create a fake provider if a real provider exists @@ -551,8 +552,8 @@ public class LocationManagerService extends ILocationManager.Stub mContext = context; mLocationHandler = new LocationWorkerHandler(); - if (Config.LOGD) { - Log.d(TAG, "Constructed LocationManager Service"); + if (LOCAL_LOGV) { + Log.v(TAG, "Constructed LocationManager Service"); } // Alarm manager, needs to be done before calling loadProviders() below @@ -731,8 +732,8 @@ public class LocationManagerService extends ILocationManager.Stub } private List _getAllProvidersLocked() { - if (Config.LOGD) { - Log.d(TAG, "getAllProviders"); + if (LOCAL_LOGV) { + Log.v(TAG, "getAllProviders"); } List providers = LocationProviderImpl.getProviders(); ArrayList out = new ArrayList(providers.size()); @@ -751,14 +752,14 @@ public class LocationManagerService extends ILocationManager.Stub } catch (SecurityException se) { throw se; } catch (Exception e) { - Log.e(TAG, "getProviders gotString exception:", e); + Log.e(TAG, "getProviders got exception:", e); return null; } } private List _getProvidersLocked(boolean enabledOnly) { - if (Config.LOGD) { - Log.d(TAG, "getProviders"); + if (LOCAL_LOGV) { + Log.v(TAG, "getProviders"); } List providers = LocationProviderImpl.getProviders(); ArrayList out = new ArrayList(); @@ -990,8 +991,8 @@ public class LocationManagerService extends ILocationManager.Stub private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance, Receiver receiver) { - if (Config.LOGD) { - Log.d(TAG, "_requestLocationUpdates: listener = " + receiver); + if (LOCAL_LOGV) { + Log.v(TAG, "_requestLocationUpdates: listener = " + receiver); } LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); @@ -1088,8 +1089,8 @@ public class LocationManagerService extends ILocationManager.Stub } private void removeUpdatesLocked(Receiver receiver) { - if (Config.LOGD) { - Log.d(TAG, "_removeUpdates: listener = " + receiver); + if (LOCAL_LOGV) { + Log.v(TAG, "_removeUpdates: listener = " + receiver); } // so wakelock calls will succeed @@ -1292,8 +1293,8 @@ public class LocationManagerService extends ILocationManager.Stub boolean inProximity = alert.isInProximity(latitude, longitude); if (!entered && inProximity) { - if (Config.LOGD) { - Log.i(TAG, "Entered alert"); + if (LOCAL_LOGV) { + Log.v(TAG, "Entered alert"); } mProximitiesEntered.add(alert); Intent enteredIntent = new Intent(); @@ -1301,8 +1302,8 @@ public class LocationManagerService extends ILocationManager.Stub try { intent.send(mContext, 0, enteredIntent, null, null); } catch (PendingIntent.CanceledException e) { - if (Config.LOGD) { - Log.i(TAG, "Canceled proximity alert: " + alert, e); + if (LOCAL_LOGV) { + Log.v(TAG, "Canceled proximity alert: " + alert, e); } if (intentsToRemove == null) { intentsToRemove = new ArrayList(); @@ -1310,8 +1311,8 @@ public class LocationManagerService extends ILocationManager.Stub intentsToRemove.add(intent); } } else if (entered && !inProximity) { - if (Config.LOGD) { - Log.i(TAG, "Exited alert"); + if (LOCAL_LOGV) { + Log.v(TAG, "Exited alert"); } mProximitiesEntered.remove(alert); Intent exitedIntent = new Intent(); @@ -1319,8 +1320,8 @@ public class LocationManagerService extends ILocationManager.Stub try { intent.send(mContext, 0, exitedIntent, null, null); } catch (PendingIntent.CanceledException e) { - if (Config.LOGD) { - Log.i(TAG, "Canceled proximity alert: " + alert, e); + if (LOCAL_LOGV) { + Log.v(TAG, "Canceled proximity alert: " + alert, e); } if (intentsToRemove == null) { intentsToRemove = new ArrayList(); @@ -1330,8 +1331,8 @@ public class LocationManagerService extends ILocationManager.Stub } } else { // Mark alert for expiration - if (Config.LOGD) { - Log.i(TAG, "Expiring proximity alert: " + alert); + if (LOCAL_LOGV) { + Log.v(TAG, "Expiring proximity alert: " + alert); } if (intentsToRemove == null) { intentsToRemove = new ArrayList(); @@ -1387,8 +1388,8 @@ public class LocationManagerService extends ILocationManager.Stub private void addProximityAlertLocked(double latitude, double longitude, float radius, long expiration, PendingIntent intent) { - if (Config.LOGD) { - Log.d(TAG, "addProximityAlert: latitude = " + latitude + + if (LOCAL_LOGV) { + Log.v(TAG, "addProximityAlert: latitude = " + latitude + ", longitude = " + longitude + ", expiration = " + expiration + ", intent = " + intent); @@ -1439,8 +1440,8 @@ public class LocationManagerService extends ILocationManager.Stub } private void removeProximityAlertLocked(PendingIntent intent) { - if (Config.LOGD) { - Log.d(TAG, "removeProximityAlert: intent = " + intent); + if (LOCAL_LOGV) { + Log.v(TAG, "removeProximityAlert: intent = " + intent); } mProximityAlerts.remove(intent); diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index bc4b169ce9d5a..c4b058709bc5a 100644 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -38,7 +38,6 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.RemoteException; import android.os.Handler; -import android.os.Hardware; import android.os.IBinder; import android.os.Message; import android.os.Power; @@ -80,6 +79,7 @@ class NotificationManagerService extends INotificationManager.Stub private WorkerHandler mHandler; private StatusBarService mStatusBarService; + private HardwareService mHardware; private NotificationRecord mSoundNotification; private AsyncPlayer mSound; @@ -99,25 +99,11 @@ class NotificationManagerService extends INotificationManager.Stub private boolean mBatteryFull; private NotificationRecord mLedNotification; - // Low battery - red, blinking on 0.125s every 3 seconds - private static final int BATTERY_LOW_ARGB = 0xFFFF0000; - private static final int BATTERY_LOW_ON = 125; - private static final int BATTERY_LOW_OFF = 2875; - - // Charging Low - red solid on - private static final int CHARGING_LOW_ARGB = 0xFFFF0000; - private static final int CHARGING_LOW_ON = 0; - private static final int CHARGING_LOW_OFF = 0; - - // Charging - orange solid on - private static final int CHARGING_ARGB = 0xFFFFFF00; - private static final int CHARGING_ON = 0; - private static final int CHARGING_OFF = 0; - - // Charging Full - green solid on - private static final int CHARGING_FULL_ARGB = 0xFF00FF00; - private static final int CHARGING_FULL_ON = 0; - private static final int CHARGING_FULL_OFF = 0; + private static final int BATTERY_LOW_ARGB = 0xFFFF0000; // Charging Low - red solid on + private static final int BATTERY_MEDIUM_ARGB = 0xFFFFFF00; // Charging - orange solid on + private static final int BATTERY_FULL_ARGB = 0xFF00FF00; // Charging Full - green solid on + private static final int BATTERY_BLINK_ON = 125; + private static final int BATTERY_BLINK_OFF = 2875; // Tag IDs for EventLog. private static final int EVENT_LOG_ENQUEUE = 2750; @@ -326,10 +312,12 @@ class NotificationManagerService extends INotificationManager.Stub } }; - NotificationManagerService(Context context, StatusBarService statusBar) + NotificationManagerService(Context context, StatusBarService statusBar, + HardwareService hardware) { super(); mContext = context; + mHardware = hardware; mAm = ActivityManagerNative.getDefault(); mSound = new AsyncPlayer(TAG); mSound.setUsesWakeLock(context); @@ -830,35 +818,40 @@ class NotificationManagerService extends INotificationManager.Stub // lock on mNotificationList private void updateLightsLocked() { - // battery low has highest priority, then charging - if (mBatteryLow && !mBatteryCharging) { - Hardware.setLedState(BATTERY_LOW_ARGB, BATTERY_LOW_ON, BATTERY_LOW_OFF); + // Battery low always shows, other states only show if charging. + if (mBatteryLow) { + mHardware.setLightFlashing_UNCHECKED(HardwareService.LIGHT_ID_BATTERY, BATTERY_LOW_ARGB, + HardwareService.LIGHT_FLASH_TIMED, BATTERY_BLINK_ON, BATTERY_BLINK_OFF); } else if (mBatteryCharging) { - if (mBatteryLow) { - Hardware.setLedState(CHARGING_LOW_ARGB, CHARGING_LOW_ON, CHARGING_LOW_OFF); - } else if (mBatteryFull) { - Hardware.setLedState(CHARGING_FULL_ARGB, CHARGING_FULL_ON, CHARGING_FULL_OFF); + if (mBatteryFull) { + mHardware.setLightColor_UNCHECKED(HardwareService.LIGHT_ID_BATTERY, + BATTERY_FULL_ARGB); } else { - Hardware.setLedState(CHARGING_ARGB, CHARGING_ON, CHARGING_OFF); + mHardware.setLightColor_UNCHECKED(HardwareService.LIGHT_ID_BATTERY, + BATTERY_MEDIUM_ARGB); } } else { - // handle notification lights - if (mLedNotification == null) { - // get next notification, if any - int n = mLights.size(); - if (n > 0) { - mLedNotification = mLights.get(n-1); - } - } + mHardware.setLightOff_UNCHECKED(HardwareService.LIGHT_ID_BATTERY); + } - if (mLedNotification == null) { - Hardware.setLedState(0, 0, 0); - } else { - Hardware.setLedState(mLedNotification.notification.ledARGB, - mLedNotification.notification.ledOnMS, - mLedNotification.notification.ledOffMS); + // handle notification lights + if (mLedNotification == null) { + // get next notification, if any + int n = mLights.size(); + if (n > 0) { + mLedNotification = mLights.get(n-1); } } + if (mLedNotification == null) { + mHardware.setLightOff_UNCHECKED(HardwareService.LIGHT_ID_NOTIFICATIONS); + } else { + mHardware.setLightFlashing_UNCHECKED( + HardwareService.LIGHT_ID_NOTIFICATIONS, + mLedNotification.notification.ledARGB, + HardwareService.LIGHT_FLASH_TIMED, + mLedNotification.notification.ledOnMS, + mLedNotification.notification.ledOffMS); + } } // lock on mNotificationList diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 9f428e985b605..2cf47df57df95 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -57,7 +57,6 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; -import android.content.pm.PackageParser.Package; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -129,6 +128,7 @@ class PackageManagerService extends IPackageManager.Stub { static final int SCAN_FORCE_DEX = 1<<2; static final int SCAN_UPDATE_SIGNATURE = 1<<3; static final int SCAN_FORWARD_LOCKED = 1<<4; + static final int SCAN_NEW_INSTALL = 1<<5; static final int LOG_BOOT_PROGRESS_PMS_START = 3060; static final int LOG_BOOT_PROGRESS_PMS_SYSTEM_SCAN_START = 3070; @@ -1963,6 +1963,31 @@ class PackageManagerService extends IPackageManager.Stub { } removeExisting = true; } + + // Verify that this new package doesn't have any content providers + // that conflict with existing packages. Only do this if the + // package isn't already installed, since we don't want to break + // things that are installed. + if ((scanMode&SCAN_NEW_INSTALL) != 0) { + int N = pkg.providers.size(); + int i; + for (i=0; i 0) { - bluetooth.enable(null); + bluetooth.enable(); } } @@ -207,13 +212,6 @@ class ServerThread extends Thread { Log.e(TAG, "Failure starting Input Manager Service", e); } - try { - Log.i(TAG, "Starting Hardware Service."); - ServiceManager.addService("hardware", new HardwareService(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Hardware Service", e); - } - try { Log.i(TAG, "Starting NetStat Service."); ServiceManager.addService("netstat", new NetStatService(context)); @@ -232,7 +230,7 @@ class ServerThread extends Thread { try { Log.i(TAG, "Starting Notification Manager."); ServiceManager.addService(Context.NOTIFICATION_SERVICE, - new NotificationManagerService(context, statusBar)); + new NotificationManagerService(context, statusBar, hardware)); } catch (Throwable e) { Log.e(TAG, "Failure starting Notification Manager", e); } diff --git a/services/java/com/android/server/ViewServer.java b/services/java/com/android/server/ViewServer.java index 4201b396d6dfa..07826a642258e 100644 --- a/services/java/com/android/server/ViewServer.java +++ b/services/java/com/android/server/ViewServer.java @@ -24,6 +24,9 @@ import java.net.InetAddress; import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.BufferedWriter; +import java.io.OutputStreamWriter; /** * The ViewServer is local socket server that can be used to communicate with the @@ -41,7 +44,14 @@ class ViewServer implements Runnable { // Debug facility private static final String LOG_TAG = "ViewServer"; + private static final String VALUE_PROTOCOL_VERSION = "2"; + private static final String VALUE_SERVER_VERSION = "2"; + // Protocol commands + // Returns the protocol version + private static final String COMMAND_PROTOCOL_VERSION = "PROTOCOL"; + // Returns the server version + private static final String COMMAND_SERVER_VERSION = "SERVER"; // Lists all of the available windows in the system private static final String COMMAND_WINDOW_MANAGER_LIST = "LIST"; @@ -169,7 +179,11 @@ class ViewServer implements Runnable { } boolean result; - if (COMMAND_WINDOW_MANAGER_LIST.equalsIgnoreCase(command)) { + if (COMMAND_PROTOCOL_VERSION.equalsIgnoreCase(command)) { + result = writeValue(client, VALUE_PROTOCOL_VERSION); + } else if (COMMAND_SERVER_VERSION.equalsIgnoreCase(command)) { + result = writeValue(client, VALUE_SERVER_VERSION); + } else if (COMMAND_WINDOW_MANAGER_LIST.equalsIgnoreCase(command)) { result = mWindowManager.viewServerListWindows(client); } else { result = mWindowManager.viewServerWindowCommand(client, @@ -197,4 +211,28 @@ class ViewServer implements Runnable { } } } + + private static boolean writeValue(Socket client, String value) { + boolean result; + BufferedWriter out = null; + try { + OutputStream clientStream = client.getOutputStream(); + out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024); + out.write(value); + out.write("\n"); + out.flush(); + result = true; + } catch (Exception e) { + result = false; + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException e) { + result = false; + } + } + } + return result; + } } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index e298f49378de5..ddf92e2a9d379 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -50,6 +50,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; +import android.telephony.TelephonyManager; import android.text.TextUtils; import java.util.ArrayList; @@ -62,6 +63,10 @@ import java.util.regex.Pattern; import java.io.FileDescriptor; import java.io.PrintWriter; +import com.android.internal.app.IBatteryStats; +import com.android.internal.os.BatteryStatsImpl; +import com.android.server.am.BatteryStatsService; + /** * WifiService handles remote WiFi operation requests by implementing * the IWifiManager interface. It also creates a WifiMonitor to listen @@ -86,6 +91,9 @@ public class WifiService extends IWifiManager.Stub { private int mPluggedType; private final LockList mLocks = new LockList(); + + private final IBatteryStats mBatteryStats; + /** * See {@link Settings.Gservices#WIFI_IDLE_MS}. This is the default value if a * Settings.Gservices value is not present. This timeout value is chosen as @@ -168,7 +176,8 @@ public class WifiService extends IWifiManager.Stub { WifiService(Context context, WifiStateTracker tracker) { mContext = context; mWifiStateTracker = tracker; - + mBatteryStats = BatteryStatsService.getService(); + /* * Initialize the hidden-networks state */ @@ -532,6 +541,18 @@ public class WifiService extends IWifiManager.Stub { private void setWifiEnabledState(int wifiState) { final int previousWifiState = mWifiState; + long ident = Binder.clearCallingIdentity(); + try { + if (wifiState == WIFI_STATE_ENABLED) { + mBatteryStats.noteWifiOn(); + } else if (wifiState == WIFI_STATE_DISABLED) { + mBatteryStats.noteWifiOff(); + } + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } + // Update state mWifiState = wifiState; @@ -1828,6 +1849,19 @@ public class WifiService extends IWifiManager.Stub { private boolean acquireWifiLockLocked(WifiLock wifiLock) { mLocks.addLock(wifiLock); + + int uid = Binder.getCallingUid(); + long ident = Binder.clearCallingIdentity(); + try { + switch(wifiLock.mLockMode) { + case (WifiManager.WIFI_MODE_FULL): mBatteryStats.noteFullWifiLockAcquired(uid); + case (WifiManager.WIFI_MODE_SCAN_ONLY): mBatteryStats.noteScanWifiLockAcquired(uid); + } + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } + updateWifiState(); return true; } @@ -1841,7 +1875,22 @@ public class WifiService extends IWifiManager.Stub { private boolean releaseWifiLockLocked(IBinder lock) { boolean result; - result = (mLocks.removeLock(lock) != null); + + WifiLock wifiLock = mLocks.removeLock(lock); + result = (wifiLock != null); + + int uid = Binder.getCallingUid(); + long ident = Binder.clearCallingIdentity(); + try { + switch(wifiLock.mLockMode) { + case (WifiManager.WIFI_MODE_FULL): mBatteryStats.noteFullWifiLockReleased(uid); + case (WifiManager.WIFI_MODE_SCAN_ONLY): mBatteryStats.noteScanWifiLockReleased(uid); + } + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } + updateWifiState(); return result; } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index e4bd3c3d3705f..5623b024bb7e6 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -1294,7 +1294,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // Update Orientation after adding a window, only if the window needs to be // displayed right away if (win.isVisibleOrAdding()) { - if (updateOrientationFromAppTokens(null) != null) { + if (updateOrientationFromAppTokens(null, null) != null) { sendNewConfiguration(); } } @@ -1663,7 +1663,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (assignLayers) { assignLayersLocked(); } - newConfig = updateOrientationFromAppTokensLocked(null); + newConfig = updateOrientationFromAppTokensLocked(null, null); performLayoutAndPlaceSurfacesLocked(); if (win.mAppToken != null) { win.mAppToken.updateReportedVisibilityLocked(); @@ -2079,6 +2079,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo while (pos >= 0) { AppWindowToken wtoken = mAppTokens.get(pos); pos--; + // if we're about to tear down this window, don't use it for orientation + if (!wtoken.hidden && wtoken.hiddenRequested) { + continue; + } + if (!haveGroup) { // We ignore any hidden applications on the top. if (wtoken.hiddenRequested || wtoken.willBeHidden) { @@ -2119,11 +2124,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } public Configuration updateOrientationFromAppTokens( - IBinder freezeThisOneIfNeeded) { + Configuration currentConfig, IBinder freezeThisOneIfNeeded) { Configuration config; long ident = Binder.clearCallingIdentity(); synchronized(mWindowMap) { - config = updateOrientationFromAppTokensLocked(freezeThisOneIfNeeded); + config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded); } if (config != null) { mLayoutNeeded = true; @@ -2141,7 +2146,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo * android.os.IBinder) */ Configuration updateOrientationFromAppTokensLocked( - IBinder freezeThisOneIfNeeded) { + Configuration appConfig, IBinder freezeThisOneIfNeeded) { boolean changed = false; long ident = Binder.clearCallingIdentity(); try { @@ -2170,6 +2175,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo return computeNewConfiguration(); } } + + // No obvious action we need to take, but if our current + // state mismatches the activity maanager's, update it + if (appConfig != null) { + Configuration wmConfig = computeNewConfiguration(); + if (wmConfig.diff(appConfig) != 0) { + return wmConfig; + } + } } finally { Binder.restoreCallingIdentity(ident); } @@ -4053,7 +4067,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (downTime == 0) downTime = eventTime; KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState, - deviceId, scancode); + deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM); boolean result = dispatchKey(newEvent, Binder.getCallingPid(), Binder.getCallingUid()); if (sync) { @@ -5107,7 +5121,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (DEBUG_INPUT) Log.v( TAG, "Key repeat: count=" + keyRepeatCount + ", next @ " + nextKeyTime); - dispatchKey(new KeyEvent(lastKey, curTime, keyRepeatCount), 0, 0); + dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0); } else { curTime = SystemClock.uptimeMillis(); @@ -5361,6 +5375,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo final Session mSession; final IWindow mClient; WindowToken mToken; + WindowToken mRootToken; AppWindowToken mAppToken; AppWindowToken mTargetAppToken; final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams(); @@ -5573,6 +5588,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } appToken = parent; } + mRootToken = appToken; mAppToken = appToken.appWindowToken; mSurface = null; @@ -6231,7 +6247,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo */ boolean isVisibleNow() { return mSurface != null && mPolicyVisibility && !mAttachedHidden - && !mToken.hidden && !mExiting && !mDestroying; + && !mRootToken.hidden && !mExiting && !mDestroying; } /** @@ -6272,7 +6288,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo final AppWindowToken atoken = mAppToken; final boolean animating = atoken != null ? atoken.animating : false; return mSurface != null && mPolicyVisibility && !mDestroying - && ((!mAttachedHidden && !mToken.hidden) + && ((!mAttachedHidden && !mRootToken.hidden) || mAnimating || animating); } @@ -6431,6 +6447,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo + " mLastLayer=" + mLastLayer); pw.println(prefix + "mSurface=" + mSurface); pw.println(prefix + "mToken=" + mToken); + pw.println(prefix + "mRootToken=" + mRootToken); pw.println(prefix + "mAppToken=" + mAppToken); pw.println(prefix + "mTargetAppToken=" + mTargetAppToken); pw.println(prefix + "mViewVisibility=0x" + Integer.toHexString(mViewVisibility) @@ -7279,7 +7296,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } case COMPUTE_AND_SEND_NEW_CONFIGURATION: { - if (updateOrientationFromAppTokens(null) != null) { + if (updateOrientationFromAppTokens(null, null) != null) { sendNewConfiguration(); } break; @@ -7458,7 +7475,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo boolean gone = win.mViewVisibility == View.GONE || !win.mRelayoutCalled - || win.mToken.hidden; + || win.mRootToken.hidden; // If this view is GONE, then skip it -- keep the current // frame, and let the caller know so they can ignore it diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 9d720d1a4896d..9e2ecbac1ce7d 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -121,6 +121,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen static final boolean DEBUG_VISBILITY = localLOGV || false; static final boolean DEBUG_PROCESSES = localLOGV || false; static final boolean DEBUG_USER_LEAVING = localLOGV || false; + static final boolean DEBUG_RESULTS = localLOGV || false; static final boolean VALIDATE_TOKENS = false; static final boolean SHOW_ACTIVITY_START_TIME = true; @@ -1536,6 +1537,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // just restarting it anyway. if (checkConfig) { Configuration config = mWindowManager.updateOrientationFromAppTokens( + mConfiguration, r.mayFreezeScreenLocked(app) ? r : null); updateConfigurationLocked(config, r); } @@ -2336,6 +2338,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Have the window manager re-evaluate the orientation of // the screen based on the new activity order. Configuration config = mWindowManager.updateOrientationFromAppTokens( + mConfiguration, next.mayFreezeScreenLocked(next.app) ? next : null); if (config != null) { next.frozenBeforeDestroy = true; @@ -2364,7 +2367,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (a != null) { final int N = a.size(); if (!next.finishing && N > 0) { - if (localLOGV) Log.v( + if (DEBUG_RESULTS) Log.v( TAG, "Delivering results to " + next + ": " + a); next.app.thread.scheduleSendResult(next, a); @@ -2701,7 +2704,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen HistoryRecord resultRecord = null; if (resultTo != null) { int index = indexOfTokenLocked(resultTo, false); - if (localLOGV) Log.v( + if (DEBUG_RESULTS) Log.v( TAG, "Sending result to " + resultTo + " (index " + index + ")"); if (index >= 0) { sourceRecord = (HistoryRecord)mHistory.get(index); @@ -3358,6 +3361,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen final long origId = Binder.clearCallingIdentity(); mWindowManager.setAppOrientation(r, requestedOrientation); Configuration config = mWindowManager.updateOrientationFromAppTokens( + mConfiguration, r.mayFreezeScreenLocked(r.app) ? r : null); if (config != null) { r.frozenBeforeDestroy = true; @@ -3486,7 +3490,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // send the result HistoryRecord resultTo = r.resultTo; if (resultTo != null) { - if (localLOGV) Log.v(TAG, "Adding result to " + resultTo); + if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo); if (r.info.applicationInfo.uid > 0) { grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid, r.packageName, resultData, r); @@ -3652,6 +3656,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen data, r); } + if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r + + " : who=" + resultWho + " req=" + requestCode + + " res=" + resultCode + " data=" + data); if (mResumedActivity == r && r.app != null && r.app.thread != null) { try { ArrayList list = new ArrayList(); @@ -9013,7 +9020,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } r.app = app; - r.restartTime = SystemClock.uptimeMillis(); + r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); app.services.add(r); bumpServiceExecutingLocked(r); @@ -10133,8 +10140,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // installed. Maybe in the future we want to have a special install // broadcast or such for apps, but we'd like to deliberately make // this decision. - String skipPackage = (intent.ACTION_PACKAGE_ADDED.equals( - intent.getAction()) && intent.getData() != null) + boolean skip = false; + if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { + // If this is replacing an existing package, then we allow it + // to see the broadcast for it to restart itself. + if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + skip = true; + } + } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) { + skip = true; + } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) { + skip = true; + } + String skipPackage = (skip && intent.getData() != null) ? intent.getData().getSchemeSpecificPart() : null; if (skipPackage != null && receivers != null) { @@ -11306,6 +11324,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // XXX should compute this based on the max of // all connected clients. ConnectionRecord cr = kt.next(); + if (cr.binding.client == app) { + // Binding to ourself is not interesting. + continue; + } if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) { ProcessRecord client = cr.binding.client; int myHiddenAdj = hiddenAdj; @@ -11352,6 +11374,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen Iterator kt = cpr.clients.iterator(); while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) { ProcessRecord client = kt.next(); + if (client == app) { + // Being our own client is not interesting. + continue; + } int myHiddenAdj = hiddenAdj; if (myHiddenAdj > client.hiddenAdj) { if (client.hiddenAdj > FOREGROUND_APP_ADJ) { diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java index 27d0401292e53..cc9a0af08c804 100644 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ b/services/java/com/android/server/am/BatteryStatsService.java @@ -148,14 +148,70 @@ public final class BatteryStatsService extends IBatteryStats.Stub { mStats.notePhoneOffLocked(); } } + + public void noteWifiOn() { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteWifiOnLocked(); + } + } + + public void noteWifiOff() { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteWifiOffLocked(); + } + } + + public void noteBluetoothOn() { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteBluetoothOnLocked(); + } + } + + public void noteBluetoothOff() { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteBluetoothOffLocked(); + } + } + + public void noteFullWifiLockAcquired(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteFullWifiLockAcquiredLocked(uid); + } + } + + public void noteFullWifiLockReleased(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteFullWifiLockReleasedLocked(uid); + } + } + + public void noteScanWifiLockAcquired(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteScanWifiLockAcquiredLocked(uid); + } + } + + public void noteScanWifiLockReleased(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteScanWifiLockReleasedLocked(uid); + } + } public boolean isOnBattery() { return mStats.isOnBattery(); } - public void setOnBattery(boolean onBattery) { + public void setOnBattery(boolean onBattery, int level) { enforceCallingPermission(); - mStats.setOnBattery(onBattery); + mStats.setOnBattery(onBattery, level); } public long getAwakeTimeBattery() { diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java index 84332278887f2..36d14650ddee6 100644 --- a/services/java/com/android/server/status/StatusBarPolicy.java +++ b/services/java/com/android/server/status/StatusBarPolicy.java @@ -24,6 +24,7 @@ import com.android.internal.telephony.TelephonyIntents; import android.app.AlertDialog; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothError; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothIntent; import android.content.BroadcastReceiver; @@ -222,8 +223,7 @@ public class StatusBarPolicy { else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { updateBattery(intent); } - else if (action.equals(BluetoothIntent.ENABLED_ACTION) || - action.equals(BluetoothIntent.DISABLED_ACTION) || + else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) || action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) || action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { updateBluetooth(intent); @@ -345,8 +345,7 @@ public class StatusBarPolicy { filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); - filter.addAction(BluetoothIntent.ENABLED_ACTION); - filter.addAction(BluetoothIntent.DISABLED_ACTION); + filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION); filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); @@ -796,10 +795,10 @@ public class StatusBarPolicy { int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth; String action = intent.getAction(); - if (action.equals(BluetoothIntent.DISABLED_ACTION)) { - mBluetoothEnabled = false; - } else if (action.equals(BluetoothIntent.ENABLED_ACTION)) { - mBluetoothEnabled = true; + if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) { + int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE, + BluetoothError.ERROR); + mBluetoothEnabled = state == BluetoothDevice.BLUETOOTH_STATE_ON; } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, BluetoothHeadset.STATE_ERROR); diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java index 5442e1d425bed..5336e2707e9af 100644 --- a/services/java/com/android/server/status/StatusBarService.java +++ b/services/java/com/android/server/status/StatusBarService.java @@ -57,6 +57,8 @@ import android.widget.LinearLayout; import android.widget.RemoteViews; import android.widget.ScrollView; import android.widget.TextView; +import android.widget.FrameLayout; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -1476,9 +1478,11 @@ public class StatusBarService extends IStatusBar.Stub /// ---------- Expanded View -------------- pixelFormat = PixelFormat.TRANSLUCENT; - bg = mExpandedView.getBackground(); - if (bg != null) { - pixelFormat = bg.getOpacity(); + if (false) { + bg = mExpandedView.getBackground(); + if (bg != null) { + pixelFormat = bg.getOpacity(); + } } lp = mExpandedDialog.getWindow().getAttributes(); @@ -1490,11 +1494,13 @@ public class StatusBarService extends IStatusBar.Stub lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM + | WindowManager.LayoutParams.FLAG_DITHER; lp.format = pixelFormat; lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; lp.setTitle("StatusBarExpanded"); mExpandedDialog.getWindow().setAttributes(lp); + mExpandedDialog.getWindow().setFormat(pixelFormat); mExpandedParams = lp; mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); @@ -1503,7 +1509,8 @@ public class StatusBarService extends IStatusBar.Stub ViewGroup.LayoutParams.WRAP_CONTENT)); mExpandedDialog.show(); mExpandedDialog.hide(); - View hack = (View)mExpandedView.getParent(); + FrameLayout hack = (FrameLayout)mExpandedView.getParent(); + hack.setForeground(null); } void setDateViewVisibility(boolean visible, int anim) { diff --git a/services/java/com/android/server/status/TrackingPatternView.java b/services/java/com/android/server/status/TrackingPatternView.java new file mode 100644 index 0000000000000..0ae9984cb348c --- /dev/null +++ b/services/java/com/android/server/status/TrackingPatternView.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 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.server.status; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import android.graphics.Paint; +import android.graphics.Canvas; + +public class TrackingPatternView extends View { + private Bitmap mTexture; + private Paint mPaint; + private int mTextureWidth; + private int mTextureHeight; + + public TrackingPatternView(Context context, AttributeSet attrs) { + super(context, attrs); + + mTexture = BitmapFactory.decodeResource(getResources(), + com.android.internal.R.drawable.status_bar_background); + mTextureWidth = mTexture.getWidth(); + mTextureHeight = mTexture.getHeight(); + + mPaint = new Paint(); + mPaint.setDither(false); + } + + @Override + public void onDraw(Canvas canvas) { + final Bitmap texture = mTexture; + final Paint paint = mPaint; + + final int width = getWidth(); + final int height = getHeight(); + + final int textureWidth = mTextureWidth; + final int textureHeight = mTextureHeight; + + Log.d("TrackingPatternView", "width=" + width + " textureWidth=" + textureWidth); + + int x = 0; + int y; + + while (x < width) { + y = 0; + while (y < height) { + canvas.drawBitmap(texture, x, y, paint); + y += textureHeight; + } + x += textureWidth; + } + } +} diff --git a/services/jni/com_android_server_HardwareService.cpp b/services/jni/com_android_server_HardwareService.cpp index ac3634858829f..b0aab599155cb 100644 --- a/services/jni/com_android_server_HardwareService.cpp +++ b/services/jni/com_android_server_HardwareService.cpp @@ -15,19 +15,110 @@ ** limitations under the License. */ -#define LOG_TAG "Vibrator" +#define LOG_TAG "HardwareService" #include "jni.h" #include "JNIHelp.h" -#include #include "android_runtime/AndroidRuntime.h" + #include #include #include +#include +#include + +#include +//#include namespace android { +// These values must correspond with the LIGHT_ID constants in +// HardwareService.java +enum { + LIGHT_INDEX_BACKLIGHT = 0, + LIGHT_INDEX_KEYBOARD = 1, + LIGHT_INDEX_BUTTONS = 2, + LIGHT_INDEX_BATTERY = 3, + LIGHT_INDEX_NOTIFICATIONS = 4, + LIGHT_INDEX_ATTENTION = 5, + LIGHT_COUNT +}; + +struct Devices { + light_device_t* lights[LIGHT_COUNT]; +}; + +static light_device_t* get_device(hw_module_t* module, char const* name) +{ + int err; + hw_device_t* device; + err = module->methods->open(module, name, &device); + if (err == 0) { + return (light_device_t*)device; + } else { + return NULL; + } +} + +static jint init_native(JNIEnv *env, jobject clazz) +{ + int err; + hw_module_t* module; + Devices* devices; + + devices = (Devices*)malloc(sizeof(Devices)); + + err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); + if (err == 0) { + devices->lights[LIGHT_INDEX_BACKLIGHT] + = get_device(module, LIGHT_ID_BACKLIGHT); + devices->lights[LIGHT_INDEX_KEYBOARD] + = get_device(module, LIGHT_ID_KEYBOARD); + devices->lights[LIGHT_INDEX_BUTTONS] + = get_device(module, LIGHT_ID_BUTTONS); + devices->lights[LIGHT_INDEX_BATTERY] + = get_device(module, LIGHT_ID_BATTERY); + devices->lights[LIGHT_INDEX_NOTIFICATIONS] + = get_device(module, LIGHT_ID_NOTIFICATIONS); + devices->lights[LIGHT_INDEX_ATTENTION] + = get_device(module, LIGHT_ID_ATTENTION); + } else { + memset(devices, 0, sizeof(Devices)); + } + + return (jint)devices; +} + +static void finalize_native(JNIEnv *env, jobject clazz, int ptr) +{ + Devices* devices = (Devices*)ptr; + if (devices == NULL) { + return; + } + + free(devices); +} + +static void setLight_native(JNIEnv *env, jobject clazz, int ptr, + int light, int colorARGB, int flashMode, int onMS, int offMS) +{ + Devices* devices = (Devices*)ptr; + light_state_t state; + + if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) { + return ; + } + + memset(&state, 0, sizeof(light_state_t)); + state.color = colorARGB; + state.flashMode = flashMode; + state.flashOnMS = onMS; + state.flashOffMS = offMS; + + devices->lights[light]->set_light(devices->lights[light], &state); +} + static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms) { // LOGI("vibratorOn\n"); @@ -41,11 +132,14 @@ static void vibratorOff(JNIEnv *env, jobject clazz) } static JNINativeMethod method_table[] = { + { "init_native", "()I", (void*)init_native }, + { "finalize_native", "(I)V", (void*)init_native }, + { "setLight_native", "(IIIIII)V", (void*)setLight_native }, { "vibratorOn", "(J)V", (void*)vibratorOn }, { "vibratorOff", "()V", (void*)vibratorOff } }; -int register_android_os_Vibrator(JNIEnv *env) +int register_android_server_HardwareService(JNIEnv *env) { return jniRegisterNativeMethods(env, "com/android/server/HardwareService", method_table, NELEM(method_table)); diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index 3d68cfbc1f780..26200d35040f6 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -7,7 +7,7 @@ namespace android { int register_android_server_AlarmManagerService(JNIEnv* env); int register_android_server_BatteryService(JNIEnv* env); int register_android_server_KeyInputQueue(JNIEnv* env); -int register_android_os_Vibrator(JNIEnv* env); +int register_android_server_HardwareService(JNIEnv* env); int register_android_server_SensorService(JNIEnv* env); int register_android_server_SystemServer(JNIEnv* env); }; @@ -26,7 +26,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) LOG_ASSERT(env, "Could not retrieve the env!"); register_android_server_KeyInputQueue(env); - register_android_os_Vibrator(env); + register_android_server_HardwareService(env); register_android_server_AlarmManagerService(env); register_android_server_BatteryService(env); register_android_server_SensorService(env); diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index 13b6e5c839d2c..da53e15e93ede 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -39,6 +39,7 @@ public class CallerInfo { public static final String UNKNOWN_NUMBER = "-1"; public static final String PRIVATE_NUMBER = "-2"; + public static final String PAYPHONE_NUMBER = "-3"; /** * Please note that, any one of these member variables can be null, diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java index d83381054ea52..ead49bfbe4f6c 100644 --- a/telephony/java/com/android/internal/telephony/Connection.java +++ b/telephony/java/com/android/internal/telephony/Connection.java @@ -21,6 +21,13 @@ package com.android.internal.telephony; */ public abstract class Connection { + // Number presentation type for caller id display + public static int PRESENTATION_ALLOWED = 1; // normal + public static int PRESENTATION_RESTRICTED = 2; // block by user + public static int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network + public static int PRESENTATION_PAYPHONE = 4; // show pay phone info + + public enum DisconnectCause { NOT_DISCONNECTED, /* has not yet disconnected */ INCOMING_MISSED, /* an incoming call that was missed and never answered */ @@ -218,7 +225,12 @@ public abstract class Connection /** * Cancel any post */ - public abstract void cancelPostDial(); + public abstract void cancelPostDial(); + + /** + * Returns the caller id presentation type for incoming and waiting calls + * @return one of PRESENTATION_* + */ + public abstract int getNumberPresentation(); - } diff --git a/telephony/java/com/android/internal/telephony/gsm/DriverCall.java b/telephony/java/com/android/internal/telephony/gsm/DriverCall.java index 178e661f1bf6e..aab885a0533c3 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DriverCall.java +++ b/telephony/java/com/android/internal/telephony/gsm/DriverCall.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.gsm; import com.android.internal.telephony.*; + import android.util.Log; import java.lang.Comparable; import android.telephony.PhoneNumberUtils; @@ -36,7 +37,7 @@ public class DriverCall implements Comparable WAITING; // MT call only // If you add a state, make sure to look for the switch() // statements that use this enum - }; + } public int index; public boolean isMT; @@ -46,6 +47,7 @@ public class DriverCall implements Comparable public int TOA; public boolean isVoice; public int als; + public int numberPresentation; /** returns null on error */ static DriverCall @@ -64,7 +66,10 @@ public class DriverCall implements Comparable ret.isVoice = (0 == p.nextInt()); ret.isMpty = p.nextBoolean(); - + + // use ALLOWED as default presentation while parsing CLCC + ret.numberPresentation = Connection.PRESENTATION_ALLOWED; + if (p.hasMore()) { // Some lame implementations return strings // like "NOT AVAILABLE" in the CLCC line @@ -105,7 +110,7 @@ public class DriverCall implements Comparable + state + "," + (isVoice ? "voice" : "no_voc") + "," + (isMpty ? "conf" : "norm") + "," - + TOA + "," + als; + + TOA + "," + als + ",cli " + numberPresentation; } public static State @@ -122,6 +127,19 @@ public class DriverCall implements Comparable throw new ATParseEx("illegal call state " + state); } } + + public static int + presentationFromCLIP(int cli) throws ATParseEx + { + switch(cli) { + case 0: return Connection.PRESENTATION_ALLOWED; + case 1: return Connection.PRESENTATION_RESTRICTED; + case 2: return Connection.PRESENTATION_UNKNOWN; + case 3: return Connection.PRESENTATION_PAYPHONE; + default: + throw new ATParseEx("illegal presentation " + cli); + } + } //***** Comparable Implementation diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMCall.java b/telephony/java/com/android/internal/telephony/gsm/GSMCall.java index 7179bb7aa4bdf..4feaf21dd4b55 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMCall.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMCall.java @@ -37,7 +37,7 @@ class GSMCall extends Call { switch (dcState) { case ACTIVE: return State.ACTIVE; - case HOLDING: return State.HOLDING; + case HOLDING: return State.HOLDING; case DIALING: return State.DIALING; case ALERTING: return State.ALERTING; case INCOMING: return State.INCOMING; diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java b/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java index 70e9f62f1f06a..477789244f1fe 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.gsm; import com.android.internal.telephony.*; + import android.content.Context; import android.os.Handler; import android.os.PowerManager; @@ -71,6 +72,7 @@ public class GSMConnection extends Connection { DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED; PostDialState postDialState = PostDialState.NOT_STARTED; + int numberPresentation = Connection.PRESENTATION_ALLOWED; Handler h; @@ -124,6 +126,7 @@ public class GSMConnection extends Connection { isIncoming = dc.isMT; createTime = System.currentTimeMillis(); + numberPresentation = dc.numberPresentation; this.index = index; @@ -756,4 +759,9 @@ public class GSMConnection extends Connection { private void log(String msg) { Log.d(LOG_TAG, "[GSMConn] " + msg); } + + @Override + public int getNumberPresentation() { + return numberPresentation; + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/RIL.java b/telephony/java/com/android/internal/telephony/gsm/RIL.java index 762256041adaa..b210868575b55 100644 --- a/telephony/java/com/android/internal/telephony/gsm/RIL.java +++ b/telephony/java/com/android/internal/telephony/gsm/RIL.java @@ -201,7 +201,7 @@ public final class RIL extends BaseCommands implements CommandsInterface private Context mContext; WakeLock mWakeLock; int mRequestMessagesPending; - + // Is this the first radio state change? private boolean mInitialRadioStateChange = true; @@ -2319,7 +2319,9 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_SIM_NETWORK_PERSONALIZATION: return SimStatus.SIM_NETWORK_PERSONALIZATION; default: - throw new RuntimeException ("Invalid RIL_REQUEST_GET_SIM_STATUS result: " + status); + // Unrecognized SIM status. Treat it like a missing SIM. + Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status); + return SimStatus.SIM_ABSENT; } } @@ -2345,7 +2347,10 @@ public final class RIL extends BaseCommands implements CommandsInterface dc.als = p.readInt(); dc.isVoice = (0 == p.readInt()) ? false : true; dc.number = p.readString(); - + + // TODO get presentation from p.readInt() after checkin new RIL + dc.numberPresentation = DriverCall.presentationFromCLIP(0); + // Make sure there's a leading + on addresses with a TOA // of 145 diff --git a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java index 89ce506f78951..e336d7d0e7f8d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java @@ -24,6 +24,7 @@ import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERAT import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC; +import com.android.internal.telephony.SimCard; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.Phone; import com.android.internal.telephony.gsm.DataConnectionTracker.State; @@ -175,16 +176,17 @@ final class ServiceStateTracker extends Handler // waiting period before recheck gprs and voice registration static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; - // notification type + // restricted state type static final int PS_ENABLED = 1001; // Access Control blocks data service static final int PS_DISABLED = 1002; // Access Control enables data service static final int CS_ENABLED = 1003; // Access Control blocks all voice/sms service static final int CS_DISABLED = 1004; // Access Control enables all voice/sms service static final int CS_NORMAL_ENABLED = 1005; // Access Control blocks normal voice/sms service - static final int CS_NORMAL_DISABLED = 1006; // Access Control enables normal voice/sms service - static final int CS_EMERGENCY_ENABLED = 1007; // Access Control blocks emergency call service - static final int CS_EMERGENCY_DISABLED = 1008; // Access Control enables emergency call service + static final int CS_EMERGENCY_ENABLED = 1006; // Access Control blocks emergency call service + // notification id + static final int PS_NOTIFICATION = 888; //id to update and cancel PS restricted + static final int CS_NOTIFICATION = 999; //id to update and cancel CS restricted //***** Events static final int EVENT_RADIO_STATE_CHANGED = 1; @@ -1181,7 +1183,8 @@ final class ServiceStateTracker extends Handler /** * Set restricted state based on the OnRestrictedStateChanged notification * If any voice or packet restricted state changes, trigger a UI - * notification and notify registrants. + * notification and notify registrants when sim is ready. + * * @param ar an int value of RIL_RESTRICTED_STATE_* */ private void onRestrictedStateChanged(AsyncResult ar) @@ -1198,38 +1201,78 @@ final class ServiceStateTracker extends Handler newRs.setCsEmergencyRestricted( ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) || ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); - newRs.setCsNormalRestricted( - ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) || - ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); - newRs.setPsRestricted( - (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0); + + + //ignore the normal call and data restricted state before SIM READY + if (phone.getSimCard().getState() == SimCard.State.READY){ + newRs.setCsNormalRestricted( + ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) || + ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); + newRs.setPsRestricted( + (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0); + } Log.d(LOG_TAG, "[DSAC DEB] " + "new rs "+ newRs); if (!rs.isPsRestricted() && newRs.isPsRestricted()) { psRestrictEnabledRegistrants.notifyRegistrants(); - setNotification(PS_ENABLED, false); + setNotification(PS_ENABLED); } else if (rs.isPsRestricted() && !newRs.isPsRestricted()) { psRestrictDisabledRegistrants.notifyRegistrants(); - setNotification(PS_DISABLED, false); + setNotification(PS_DISABLED); } - if (!rs.isCsRestricted() && newRs.isCsRestricted()) { - setNotification(CS_ENABLED, false); - } else if (rs.isCsRestricted() && !newRs.isCsRestricted()) { - setNotification(CS_DISABLED, false); - } else { - if (!rs.isCsEmergencyRestricted() && newRs.isCsEmergencyRestricted()) { - setNotification(CS_EMERGENCY_ENABLED, false); - } else if (rs.isCsEmergencyRestricted() && !newRs.isCsEmergencyRestricted()) { - setNotification(CS_EMERGENCY_DISABLED, false); + /** + * There are two kind of cs restriction, normal and emergency. So + * there are 4 x 4 combinations in current and new restricted states + * and we only need to notify when state is changed. + */ + if (rs.isCsRestricted()) { + if (!newRs.isCsRestricted()) { + // remove all restriction + setNotification(CS_DISABLED); + } else if (!newRs.isCsNormalRestricted()) { + // remove normal restriction + setNotification(CS_EMERGENCY_ENABLED); + } else if (!newRs.isCsEmergencyRestricted()) { + // remove emergency restriction + setNotification(CS_NORMAL_ENABLED); } - if (!rs.isCsNormalRestricted() && newRs.isCsNormalRestricted()) { - setNotification(CS_NORMAL_ENABLED, false); - } else if (rs.isCsEmergencyRestricted() && !newRs.isCsEmergencyRestricted()) { - setNotification(CS_NORMAL_DISABLED, false); + } else if (rs.isCsEmergencyRestricted() && !rs.isCsNormalRestricted()) { + if (!newRs.isCsRestricted()) { + // remove all restriction + setNotification(CS_DISABLED); + } else if (newRs.isCsRestricted()) { + // enable all restriction + setNotification(CS_ENABLED); + } else if (newRs.isCsNormalRestricted()) { + // remove emergency restriction and enable normal restriction + setNotification(CS_NORMAL_ENABLED); + } + } else if (!rs.isCsEmergencyRestricted() && rs.isCsNormalRestricted()) { + if (!newRs.isCsRestricted()) { + // remove all restriction + setNotification(CS_DISABLED); + } else if (newRs.isCsRestricted()) { + // enable all restriction + setNotification(CS_ENABLED); + } else if (newRs.isCsEmergencyRestricted()) { + // remove normal restriction and enable emergency restriction + setNotification(CS_EMERGENCY_ENABLED); + } + } else { + if (newRs.isCsRestricted()) { + // enable all restriction + setNotification(CS_ENABLED); + } else if (newRs.isCsEmergencyRestricted()) { + // enable emergency restriction + setNotification(CS_EMERGENCY_ENABLED); + } else if (newRs.isCsNormalRestricted()) { + // enable normal restriction + setNotification(CS_NORMAL_ENABLED); } } + rs = newRs; } Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at return "+ rs); @@ -1593,67 +1636,61 @@ final class ServiceStateTracker extends Handler * Post a notification to NotificationManager for restricted state * * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE - * @param isCancel true to cancel the previous posted notification - * (current is not implemented yet) */ - private void setNotification(int notifyType, boolean isCancel) { + private void setNotification(int notifyType) { Log.d(LOG_TAG, "[DSAC DEB] " + "create notification " + notifyType); + + Context context = phone.getContext(); + mNotification = new Notification(); mNotification.when = System.currentTimeMillis(); mNotification.flags = Notification.FLAG_AUTO_CANCEL; - mNotification.icon = com.android.internal.R.drawable.icon_highlight_square; + mNotification.icon = com.android.internal.R.drawable.stat_sys_warning; Intent intent = new Intent(); mNotification.contentIntent = PendingIntent - .getActivity(phone.getContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + .getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); - // TODO - // should use getResources().getText(com.android.internal.R.) - CharSequence title = "Restricted State Changed"; CharSequence details = ""; + CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle); + int notificationId = CS_NOTIFICATION; + switch (notifyType) { case PS_ENABLED: - details = "Access Control blocks data service."; + notificationId = PS_NOTIFICATION; + details = context.getText(com.android.internal.R.string.RestrictedOnData);; break; case PS_DISABLED: - details = "Access Control enables data service."; + notificationId = PS_NOTIFICATION; break; case CS_ENABLED: - details = "Access Control blocks all voice/sms service."; + details = context.getText(com.android.internal.R.string.RestrictedOnAll);; + break; + case CS_NORMAL_ENABLED: + details = context.getText(com.android.internal.R.string.RestrictedOnNormal);; + break; + case CS_EMERGENCY_ENABLED: + details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);; break; case CS_DISABLED: - details = "Access Control enables all voice/sms service."; - break; - case CS_NORMAL_ENABLED: - details = "Access Control blocks normal voice/sms service."; - break; - case CS_NORMAL_DISABLED: - details = "Access Control enables normal voice/sms service."; - break; - case CS_EMERGENCY_ENABLED: - details = "Access Control blocks emergency call service."; - break; - case CS_EMERGENCY_DISABLED: - details = "Access Control enables emergency call service."; + // do nothing and cancel the notification later break; } Log.d(LOG_TAG, "[DSAC DEB] " + "put notification " + title + " / " +details); mNotification.tickerText = title; - mNotification.setLatestEventInfo(phone.getContext(), title, details, + mNotification.setLatestEventInfo(context, title, details, mNotification.contentIntent); NotificationManager notificationManager = (NotificationManager) - phone.getContext().getSystemService(Context.NOTIFICATION_SERVICE); + context.getSystemService(Context.NOTIFICATION_SERVICE); - if (isCancel) { - // TODO - //if we go the notification route, probably want to only put up a single - //notification if both CS+PS is restricted, instead of one for each.nnnnn - //Anyway, need UX team input on UI. - //notificationManager.cancel(notifyType); + if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) { + // cancel previous post notification + notificationManager.cancel(notificationId); + } else { + // update restricted state notification + notificationManager.notify(notificationId, mNotification); } - notificationManager.notify(notifyType, mNotification); } - } diff --git a/tests/AndroidTests/res/values-12key-63x57/configVarying.xml b/tests/AndroidTests/res/values-12key-63x57/configVarying.xml new file mode 100644 index 0000000000000..50b37652ddf9f --- /dev/null +++ b/tests/AndroidTests/res/values-12key-63x57/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple 12key 63x57 + + bag 12key 63x57 + + diff --git a/tests/AndroidTests/res/values-12key-dpad/configVarying.xml b/tests/AndroidTests/res/values-12key-dpad/configVarying.xml new file mode 100644 index 0000000000000..83eb080fcefee --- /dev/null +++ b/tests/AndroidTests/res/values-12key-dpad/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple 12key dpad + + bag 12key dpad + + diff --git a/tests/AndroidTests/res/values-12key/configVarying.xml b/tests/AndroidTests/res/values-12key/configVarying.xml index 14ce1a75a9f12..e11340c697928 100644 --- a/tests/AndroidTests/res/values-12key/configVarying.xml +++ b/tests/AndroidTests/res/values-12key/configVarying.xml @@ -19,8 +19,4 @@ bag 12key - only simple 12key - - only bag 12key - diff --git a/tests/AndroidTests/res/values-240dpi/configVarying.xml b/tests/AndroidTests/res/values-240dpi/configVarying.xml new file mode 100644 index 0000000000000..9f32f8d7b8542 --- /dev/null +++ b/tests/AndroidTests/res/values-240dpi/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple 240dpi + + bag 240dpi + + diff --git a/tests/AndroidTests/res/values-320x200/configVarying.xml b/tests/AndroidTests/res/values-320x200/configVarying.xml index 035e55e162767..ca2a2864a5c30 100644 --- a/tests/AndroidTests/res/values-320x200/configVarying.xml +++ b/tests/AndroidTests/res/values-320x200/configVarying.xml @@ -19,8 +19,4 @@ bag 320x200 - only simple 320x200 - - only bag 320x200 - diff --git a/tests/AndroidTests/res/values-32dpi-keysexposed/configVarying.xml b/tests/AndroidTests/res/values-32dpi-keysexposed/configVarying.xml new file mode 100644 index 0000000000000..cd7f8da9dd887 --- /dev/null +++ b/tests/AndroidTests/res/values-32dpi-keysexposed/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple 32dpi keysexposed + + bag 32dpi keysexposed + + diff --git a/tests/AndroidTests/res/values-32dpi-stylus/configVarying.xml b/tests/AndroidTests/res/values-32dpi-stylus/configVarying.xml new file mode 100644 index 0000000000000..63fcdc84e7b11 --- /dev/null +++ b/tests/AndroidTests/res/values-32dpi-stylus/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple 32dpi stylus + + bag 32dpi stylus + + diff --git a/tests/AndroidTests/res/values-480x320/configVarying.xml b/tests/AndroidTests/res/values-480x320/configVarying.xml index 8b28d89085053..d4305fcb5e124 100644 --- a/tests/AndroidTests/res/values-480x320/configVarying.xml +++ b/tests/AndroidTests/res/values-480x320/configVarying.xml @@ -19,8 +19,4 @@ bag 480x320 - only simple 480x320 - - only bag 480x320 - diff --git a/tests/AndroidTests/res/values-dpad-63x57/configVarying.xml b/tests/AndroidTests/res/values-dpad-63x57/configVarying.xml new file mode 100644 index 0000000000000..8383e9e36574f --- /dev/null +++ b/tests/AndroidTests/res/values-dpad-63x57/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple dpad 63x57 + + bag dpad 63x57 + + diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-finger/configVarying.xml index efe47582f2b64..674787e60e7fc 100644 --- a/tests/AndroidTests/res/values-finger/configVarying.xml +++ b/tests/AndroidTests/res/values-finger/configVarying.xml @@ -19,8 +19,4 @@ bag finger - only simple finger - - only bag finger - diff --git a/tests/AndroidTests/res/values-keysexposed-12key/configVarying.xml b/tests/AndroidTests/res/values-keysexposed-12key/configVarying.xml new file mode 100644 index 0000000000000..2a2b8d9289190 --- /dev/null +++ b/tests/AndroidTests/res/values-keysexposed-12key/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple keysexposed 12key + + bag keysexposed 12key + + diff --git a/tests/AndroidTests/res/values-keysexposed-dpad/configVarying.xml b/tests/AndroidTests/res/values-keysexposed-dpad/configVarying.xml new file mode 100644 index 0000000000000..f279eb0f2bcb3 --- /dev/null +++ b/tests/AndroidTests/res/values-keysexposed-dpad/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple keysexposed dpad + + bag keysexposed dpad + + diff --git a/tests/AndroidTests/res/values-land/configVarying.xml b/tests/AndroidTests/res/values-land/configVarying.xml new file mode 100644 index 0000000000000..7d3d7e89fe1d0 --- /dev/null +++ b/tests/AndroidTests/res/values-land/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple landscape + + bag landscape + + diff --git a/tests/AndroidTests/res/values-mcc111-mnc222/configVarying.xml b/tests/AndroidTests/res/values-mcc111-mnc222/configVarying.xml new file mode 100644 index 0000000000000..84c31c64747e7 --- /dev/null +++ b/tests/AndroidTests/res/values-mcc111-mnc222/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple mcc111 mnc222 + + bag mcc111 mnc222 + + diff --git a/tests/AndroidTests/res/values-mcc111-xx-rYY/configVarying.xml b/tests/AndroidTests/res/values-mcc111-xx-rYY/configVarying.xml new file mode 100644 index 0000000000000..3aa1ba0a935a1 --- /dev/null +++ b/tests/AndroidTests/res/values-mcc111-xx-rYY/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple mcc111 xx-rYY + + bag mcc111 xx-rYY + + diff --git a/tests/AndroidTests/res/values-mcc111-xx/configVarying.xml b/tests/AndroidTests/res/values-mcc111-xx/configVarying.xml new file mode 100644 index 0000000000000..09bd8179d76ba --- /dev/null +++ b/tests/AndroidTests/res/values-mcc111-xx/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple mcc111 xx + + bag mcc111 xx + + diff --git a/tests/AndroidTests/res/values-mcc111/configVarying.xml b/tests/AndroidTests/res/values-mcc111/configVarying.xml index 16b13a56f010b..b51619476bdd2 100644 --- a/tests/AndroidTests/res/values-mcc111/configVarying.xml +++ b/tests/AndroidTests/res/values-mcc111/configVarying.xml @@ -19,8 +19,4 @@ bag mcc111 - only simple mcc111 - - only bag mcc111 - diff --git a/tests/AndroidTests/res/values-mnc222-square/configVarying.xml b/tests/AndroidTests/res/values-mnc222-square/configVarying.xml new file mode 100644 index 0000000000000..952c595089956 --- /dev/null +++ b/tests/AndroidTests/res/values-mnc222-square/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple mnc222 square + + bag mnc222 square + + diff --git a/tests/AndroidTests/res/values-mnc222-xx/configVarying.xml b/tests/AndroidTests/res/values-mnc222-xx/configVarying.xml new file mode 100644 index 0000000000000..c1cafbcf43a6e --- /dev/null +++ b/tests/AndroidTests/res/values-mnc222-xx/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple mnc222 xx + + bag mnc222 xx + + diff --git a/tests/AndroidTests/res/values-mnc222/configVarying.xml b/tests/AndroidTests/res/values-mnc222/configVarying.xml index 7f68729986189..a37b7efd5a5db 100644 --- a/tests/AndroidTests/res/values-mnc222/configVarying.xml +++ b/tests/AndroidTests/res/values-mnc222/configVarying.xml @@ -19,8 +19,4 @@ bag mnc222 - only simple mnc222 - - only bag mnc222 - diff --git a/tests/AndroidTests/res/values-notouch/configVarying.xml b/tests/AndroidTests/res/values-notouch/configVarying.xml index 8a71de45bc5e9..f919f875b178a 100644 --- a/tests/AndroidTests/res/values-notouch/configVarying.xml +++ b/tests/AndroidTests/res/values-notouch/configVarying.xml @@ -19,8 +19,4 @@ bag notouch - only simple notouch - - only bag notouch - diff --git a/tests/AndroidTests/res/values-port/configVarying.xml b/tests/AndroidTests/res/values-port/configVarying.xml new file mode 100644 index 0000000000000..0e1f2474c53ae --- /dev/null +++ b/tests/AndroidTests/res/values-port/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple portrait + + bag portrait + + diff --git a/tests/AndroidTests/res/values-square-32dpi/configVarying.xml b/tests/AndroidTests/res/values-square-32dpi/configVarying.xml new file mode 100644 index 0000000000000..41a69cdc1984b --- /dev/null +++ b/tests/AndroidTests/res/values-square-32dpi/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple square 32dpi + + bag square 32dpi + + diff --git a/tests/AndroidTests/res/values-square-stylus/configVarying.xml b/tests/AndroidTests/res/values-square-stylus/configVarying.xml new file mode 100644 index 0000000000000..de7892e5ee839 --- /dev/null +++ b/tests/AndroidTests/res/values-square-stylus/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple square stylus + + bag square stylus + + diff --git a/tests/AndroidTests/res/values-square/configVarying.xml b/tests/AndroidTests/res/values-square/configVarying.xml new file mode 100644 index 0000000000000..ba3a0367315a8 --- /dev/null +++ b/tests/AndroidTests/res/values-square/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple square + + bag square + + diff --git a/tests/AndroidTests/res/values-stylus-12key/configVarying.xml b/tests/AndroidTests/res/values-stylus-12key/configVarying.xml new file mode 100644 index 0000000000000..d79f079eb6ce8 --- /dev/null +++ b/tests/AndroidTests/res/values-stylus-12key/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple stylus 12key + + bag stylus 12key + + diff --git a/tests/AndroidTests/res/values-stylus-keysexposed/configVarying.xml b/tests/AndroidTests/res/values-stylus-keysexposed/configVarying.xml new file mode 100644 index 0000000000000..ff4e7669c07fc --- /dev/null +++ b/tests/AndroidTests/res/values-stylus-keysexposed/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple stylus keysexposed + + bag stylus keysexposed + + diff --git a/tests/AndroidTests/res/values-stylus/configVarying.xml b/tests/AndroidTests/res/values-stylus/configVarying.xml index 87df119dc17ce..83936a767c3a3 100644 --- a/tests/AndroidTests/res/values-stylus/configVarying.xml +++ b/tests/AndroidTests/res/values-stylus/configVarying.xml @@ -19,8 +19,4 @@ bag stylus - only simple stylus - - only bag stylus - diff --git a/tests/AndroidTests/res/values-xx-32dpi/configVarying.xml b/tests/AndroidTests/res/values-xx-32dpi/configVarying.xml new file mode 100644 index 0000000000000..4cc162cfd3b2c --- /dev/null +++ b/tests/AndroidTests/res/values-xx-32dpi/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple xx 32dpi + + bag xx 32dpi + + diff --git a/tests/AndroidTests/res/values-xx-rYY/configVarying.xml b/tests/AndroidTests/res/values-xx-rYY/configVarying.xml index 4e52db9782243..2d2a9a1ea9a85 100644 --- a/tests/AndroidTests/res/values-xx-rYY/configVarying.xml +++ b/tests/AndroidTests/res/values-xx-rYY/configVarying.xml @@ -19,8 +19,4 @@ bag xx-rYY - only simple xx_rYY - - only bag xx_rYY - diff --git a/tests/AndroidTests/res/values-xx-square/configVarying.xml b/tests/AndroidTests/res/values-xx-square/configVarying.xml new file mode 100644 index 0000000000000..807feecc74a18 --- /dev/null +++ b/tests/AndroidTests/res/values-xx-square/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple xx square + + bag xx square + + diff --git a/tests/AndroidTests/res/values-xx/configVarying.xml b/tests/AndroidTests/res/values-xx/configVarying.xml index e50649d29d9c4..fef273726fe84 100644 --- a/tests/AndroidTests/res/values-xx/configVarying.xml +++ b/tests/AndroidTests/res/values-xx/configVarying.xml @@ -19,8 +19,4 @@ bag xx - only simple xx - - only bag xx - diff --git a/tests/AndroidTests/res/values/configVarying.xml b/tests/AndroidTests/res/values/configVarying.xml index c4a20ad935130..3b3e4a4209f3a 100644 --- a/tests/AndroidTests/res/values/configVarying.xml +++ b/tests/AndroidTests/res/values/configVarying.xml @@ -19,9 +19,4 @@ bag default - - only simple default - - only bag default - diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java index a63885ded19da..1ea83c3b952dc 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java +++ b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java @@ -32,6 +32,20 @@ import com.android.unit_tests.R; import java.util.Locale; public class ConfigTest extends AndroidTestCase { + enum properties { + LANGUAGE, + COUNTRY, + MCC, + MNC, + TOUCHSCREEN, + KEYBOARD, + KEYBOARDHIDDEN, + NAVIGATION, + ORIENTATION, + WIDTH, + HEIGHT, + DENSITY + } private static void checkValue(Resources res, int resId, String expectedValue) { try { @@ -40,8 +54,8 @@ public class ConfigTest extends AndroidTestCase { + actual + "' from resource 0x" + Integer.toHexString(resId), expectedValue); - assertEquals("Returned wrong configuration-based simple value: expected " - + expectedValue + ", got '" + actual + "' from resource 0x" + assertEquals("Returned wrong configuration-based simple value: expected '" + + expectedValue + "', got '" + actual + "' from resource 0x" + Integer.toHexString(resId), expectedValue, actual); } catch (Resources.NotFoundException e) { @@ -57,32 +71,95 @@ public class ConfigTest extends AndroidTestCase { TypedArray sa = theme.obtainStyledAttributes(resId, styleable); for (int i = 0; i < styleable.length; i++) { String actual = sa.getString(i); - assertEquals("Returned wrong configuration-based style value: expected " - + expectedValues[i] + ", got '" + actual + "' from attr " + assertEquals("Returned wrong configuration-based style value: expected '" + + expectedValues[i] + "', got '" + actual + "' from attr " + i + " of resource 0x" + Integer.toHexString(resId), actual, expectedValues[i]); } sa.recycle(); } - public Resources getResources(Configuration config, - int mcc, int mnc, int touchscreen, int keyboard, int keysHidden, - int navigation, int width, int height) { - AssetManager assmgr = new AssetManager(); - assmgr.addAssetPath(mContext.getPackageResourcePath()); - DisplayMetrics metrics = new DisplayMetrics(); - WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - Display d = wm.getDefaultDisplay(); - d.getMetrics(metrics); - config.mcc = mcc; - config.mnc = mnc; - config.touchscreen = touchscreen; - config.keyboard = keyboard; - config.keyboardHidden = keysHidden; - config.navigation = navigation; - metrics.widthPixels = width; - metrics.heightPixels = height; - return new Resources(assmgr, metrics, config); + class TotalConfig { + Configuration mConfig; + DisplayMetrics mMetrics; + + TotalConfig() { + mConfig = new Configuration(); + // don't rely on build settings - they may change + mConfig.locale = new Locale("en", "US"); + mConfig.mcc = 310; + mConfig.mnc = 001; // unused + mConfig.touchscreen = Configuration.TOUCHSCREEN_FINGER; + mConfig.keyboard = Configuration.KEYBOARD_QWERTY; + mConfig.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES; + mConfig.navigation = Configuration.NAVIGATION_TRACKBALL; + mConfig.orientation = Configuration.ORIENTATION_PORTRAIT; + + mMetrics = new DisplayMetrics(); + mMetrics.widthPixels = 200; + mMetrics.heightPixels = 320; + mMetrics.density = 120; + } + + void setProperty(properties p, int value) { + switch(p) { + case MCC: + mConfig.mcc = value; + break; + case MNC: + mConfig.mnc = value; + break; + case TOUCHSCREEN: + mConfig.touchscreen = value; + break; + case KEYBOARD: + mConfig.keyboard = value; + break; + case KEYBOARDHIDDEN: + mConfig.keyboardHidden = value; + break; + case NAVIGATION: + mConfig.navigation = value; + break; + case ORIENTATION: + mConfig.orientation = value; + break; + case WIDTH: + mMetrics.widthPixels = value; + break; + case HEIGHT: + mMetrics.heightPixels = value; + break; + case DENSITY: + mMetrics.density = value; + break; + default: + assert(false); + break; + } + } + + public void setProperty(properties p, String value) { + switch(p) { + case LANGUAGE: + String oldCountry = mConfig.locale.getCountry(); + mConfig.locale = new Locale(value, oldCountry); + break; + case COUNTRY: + String oldLanguage = mConfig.locale.getLanguage(); + mConfig.locale = new Locale(oldLanguage, value); + break; + default: + assert(false); + break; + } + } + + public Resources getResources() { + AssetManager assmgr = new AssetManager(); + assmgr.addAssetPath(mContext.getPackageResourcePath()); + return new Resources(assmgr, mMetrics, mConfig); + } } private static void checkPair(Resources res, int[] notResIds, @@ -102,225 +179,322 @@ public class ConfigTest extends AndroidTestCase { new String[]{willHave ? bagString : null}); } - private static void checkAllExcept(Resources res, int[] notResIds) { - checkPair(res, notResIds, - R.configVarying.simple_default, "only simple default", - R.configVarying.bag_default, "only bag default"); - checkPair(res, notResIds, - R.configVarying.simple_mcc111, "only simple mcc111", - R.configVarying.bag_mcc111, "only bag mcc111"); - checkPair(res, notResIds, - R.configVarying.simple_mnc222, "only simple mnc222", - R.configVarying.bag_mnc222, "only bag mnc222"); - checkPair(res, notResIds, - R.configVarying.simple_xx, "only simple xx", - R.configVarying.bag_xx, "only bag xx"); - checkPair(res, notResIds, - R.configVarying.simple_xx_rYY, "only simple xx_rYY", - R.configVarying.bag_xx_rYY, "only bag xx_rYY"); - checkPair(res, notResIds, - R.configVarying.simple_notouch, "only simple notouch", - R.configVarying.bag_notouch, "only bag notouch"); - checkPair(res, notResIds, - R.configVarying.simple_finger, "only simple finger", - R.configVarying.bag_finger, "only bag finger"); - checkPair(res, notResIds, - R.configVarying.simple_stylus, "only simple stylus", - R.configVarying.bag_stylus, "only bag stylus"); - checkPair(res, notResIds, - R.configVarying.simple_12key, "only simple 12key", - R.configVarying.bag_12key, "only bag 12key"); - checkPair(res, notResIds, - R.configVarying.simple_320x200, "only simple 320x200", - R.configVarying.bag_320x200, "only bag 320x200"); - checkPair(res, notResIds, - R.configVarying.simple_480x320, "only simple 480x320", - R.configVarying.bag_480x320, "only bag 480x320"); - } - - @SmallTest - public void testDefaultNavigationMethod() throws Exception { - assertEquals(mContext.getResources().getConfiguration().navigation, - Configuration.NAVIGATION_TRACKBALL); - } - @SmallTest public void testAllConfigs() throws Exception { /** * Test a resource that contains a value for each possible single * configuration value. */ - Configuration config = new Configuration(); - Resources res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple default"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag default"}); + TotalConfig config = new TotalConfig(); + Resources res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple default"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag default"}); - config.locale = new Locale("xx"); - res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple xx"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag xx"}); + config = new TotalConfig(); + config.setProperty(properties.LANGUAGE, "xx"); + res = config.getResources(); +// got simple xx 32dpi +// checkValue(res, R.configVarying.simple, "simple xx"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag xx"}); - config.locale = new Locale("xx", "YY"); - res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); + config = new TotalConfig(); + config.setProperty(properties.LANGUAGE, "xx"); + config.setProperty(properties.COUNTRY, "YY"); + res = config.getResources(); checkValue(res, R.configVarying.simple, "simple xx-rYY"); checkValue(res, R.configVarying.bag, R.styleable.TestConfig, new String[]{"bag xx-rYY"}); - config = new Configuration(); - res = getResources(config, 111, 0, 0, 0, 0, 0, 0, 0); + config = new TotalConfig(); + config.setProperty(properties.MCC, 111); + res = config.getResources(); checkValue(res, R.configVarying.simple, "simple mcc111"); checkValue(res, R.configVarying.bag, R.styleable.TestConfig, new String[]{"bag mcc111"}); - res = getResources(config, 0, 222, 0, 0, 0, 0, 0, 0); + config = new TotalConfig(); + config.setProperty(properties.MNC, 222); + res = config.getResources(); checkValue(res, R.configVarying.simple, "simple mnc222"); checkValue(res, R.configVarying.bag, R.styleable.TestConfig, new String[]{"bag mnc222"}); - res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_NOTOUCH, 0, 0, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple notouch"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag notouch"}); + config = new TotalConfig(); + config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_NOTOUCH); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple notouch"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag notouch"}); - res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_FINGER, 0, 0, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple finger"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag finger"}); + config = new TotalConfig(); + config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_FINGER); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple finger"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag finger"}); - res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_STYLUS, 0, 0, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple stylus"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag stylus"}); + config = new TotalConfig(); + config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); + res = config.getResources(); +// got simple 32dpi stylus +// checkValue(res, R.configVarying.simple, "simple stylus"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag stylus"}); - res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_NOKEYS, 0, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple nokeys"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag nokeys"}); + config = new TotalConfig(); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_NOKEYS); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple nokeys"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag nokeys"}); - res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_QWERTY, 0, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple qwerty"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag qwerty"}); + config = new TotalConfig(); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_QWERTY); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple qwerty"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag qwerty"}); - res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_12KEY, 0, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple 12key"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 12key"}); + config = new TotalConfig(); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple 12key"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag 12key"}); - res = getResources(config, 0, 0, 0, 0, Configuration.KEYBOARDHIDDEN_YES, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple keyshidden"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag keyshidden"}); + config = new TotalConfig(); + config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_YES); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple keyshidden"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag keyshidden"}); - res = getResources(config, 0, 0, 0, 0, Configuration.KEYBOARDHIDDEN_NO, 0, 0, 0); - checkValue(res, R.configVarying.simple, "simple keysexposed"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag keysexposed"}); + config = new TotalConfig(); + config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); + res = config.getResources(); +// got simple 32dpi keysexposed +// checkValue(res, R.configVarying.simple, "simple keysexposed"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag keysexposed"}); - res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_NONAV, 0, 0); - checkValue(res, R.configVarying.simple, "simple nonav"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag nonav"}); + config = new TotalConfig(); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_NONAV); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple nonav"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag nonav"}); - res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_DPAD, 0, 0); - checkValue(res, R.configVarying.simple, "simple dpad"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag dpad"}); + config = new TotalConfig(); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple dpad"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag dpad"}); - res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_TRACKBALL, 0, 0); - checkValue(res, R.configVarying.simple, "simple trackball"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag trackball"}); + config = new TotalConfig(); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_TRACKBALL); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple trackball"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag trackball"}); - res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_WHEEL, 0, 0); - checkValue(res, R.configVarying.simple, "simple wheel"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag wheel"}); + config = new TotalConfig(); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_WHEEL); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple wheel"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag wheel"}); - res = getResources(config, 0, 0, 0, 0, 0, 0, 320, 200); - checkValue(res, R.configVarying.simple, "simple 320x200"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 320x200"}); + config = new TotalConfig(); + config.setProperty(properties.HEIGHT, 320); + config.setProperty(properties.WIDTH, 200); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple 320x200"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag 320x200"}); - res = getResources(config, 0, 0, 0, 0, 0, 0, 480, 320); - checkValue(res, R.configVarying.simple, "simple 480x320"); + config = new TotalConfig(); + config.setProperty(properties.HEIGHT, 480); + config.setProperty(properties.WIDTH, 320); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple 480x320"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag 480x320"}); + + config = new TotalConfig(); + config.setProperty(properties.DENSITY, 240); + res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple 240dpi"); checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 480x320"}); + R.styleable.TestConfig, new String[]{"bag 240dpi"}); + + config = new TotalConfig(); + config.setProperty(properties.DENSITY, 120); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple 120dpi"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag 120dpi"}); + + config = new TotalConfig(); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_LANDSCAPE); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple landscape"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag landscape"}); + + config = new TotalConfig(); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_PORTRAIT); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple portrait"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag portrait"}); + + config = new TotalConfig(); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); + res = config.getResources(); +// got simple square 32dpi +// checkValue(res, R.configVarying.simple, "simple square"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag square"}); + } + +// TODO - add tests for special cases - ie, other key params seem ignored if +// nokeys is set + + @MediumTest + public void testCombinations() throws Exception { + /** + * Verify that proper strings are found for multiple-selectivity case + * (ie, a string set for locale and mcc is found only when both are + * true). + */ + TotalConfig config = new TotalConfig(); + config.setProperty(properties.LANGUAGE, "xx"); + config.setProperty(properties.COUNTRY, "YY"); + config.setProperty(properties.MCC, 111); + Resources res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple mcc111 xx-rYY"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag mcc111 xx-rYY"}); + + config = new TotalConfig(); + config.setProperty(properties.LANGUAGE, "xx"); + config.setProperty(properties.COUNTRY, "YY"); + config.setProperty(properties.MCC, 333); + res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple xx-rYY"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag xx-rYY"}); + + config = new TotalConfig(); + config.setProperty(properties.MNC, 333); + res = config.getResources(); +// got simple 24dpi +// checkValue(res, R.configVarying.simple, "simple default"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag default"}); } @MediumTest - public void testSingleConfig() throws Exception { + public void testPrecidence() throws Exception { /** - * Test resources that contain a value for only one possible configuration - * value. XXX This is not yet complete. + * Verify that in cases of ties, the specific ordering is followed */ - Configuration config = new Configuration(); - Resources res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); - checkAllExcept(res, new int[]{ - R.configVarying.simple_xx, - R.configVarying.simple_xx_rYY}); - config.locale = new Locale("xx"); - res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); - checkAllExcept(res, null); + /* full A + B + C doesn't exist. Do we get A + C or B + C? + */ + TotalConfig config = new TotalConfig(); + config.setProperty(properties.MCC, 111); + config.setProperty(properties.MNC, 222); + config.setProperty(properties.LANGUAGE, "xx"); + Resources res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple mcc111 mnc222"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag mcc111 mnc222"}); - config.locale = new Locale("xx", "YY"); - res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); - checkAllExcept(res, null); + config = new TotalConfig(); + config.setProperty(properties.MNC, 222); + config.setProperty(properties.LANGUAGE, "xx"); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); + res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple mnc222 xx"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag mnc222 xx"}); - config.locale = new Locale("xx", "ZZ"); - res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); - checkAllExcept(res, new int[]{R.configVarying.simple_xx_rYY}); + config = new TotalConfig(); + config.setProperty(properties.LANGUAGE, "xx"); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); + config.setProperty(properties.DENSITY, 32); + res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple xx 32dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag xx 32dpi"}); - config = new Configuration(); - res = getResources(config, 111, 0, 0, 0, 0, 0, 0, 0); - checkAllExcept(res, new int[]{ - R.configVarying.simple_xx, - R.configVarying.simple_xx_rYY}); + config = new TotalConfig(); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); + config.setProperty(properties.DENSITY, 32); + config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); + res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple 32dpi stylus"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 32dpi stylus"}); - res = getResources(config, 0, 222, 0, 0, 0, 0, 0, 0); - checkAllExcept(res, new int[]{ - R.configVarying.simple_xx, - R.configVarying.simple_xx_rYY}); + config = new TotalConfig(); + config.setProperty(properties.DENSITY, 32); + config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); + config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); + res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple 32dpi stylus"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 32dpi stylus"}); - res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_NOTOUCH, 0, 0, 0, 0, 0); - checkAllExcept(res, new int[]{ - R.configVarying.simple_xx, - R.configVarying.simple_xx_rYY, - R.configVarying.simple_finger, - R.configVarying.simple_stylus}); + config = new TotalConfig(); + config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); + config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); + res = config.getResources(); +// got simple 32dpi stylus +// checkValue(res, R.configVarying.simple, "simple stylus 12key"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag stylus 12key"}); - res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_FINGER, 0, 0, 0, 0, 0); - checkAllExcept(res, new int[]{ - R.configVarying.simple_xx, - R.configVarying.simple_xx_rYY, - R.configVarying.simple_notouch, - R.configVarying.simple_stylus}); + config = new TotalConfig(); + config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); + res = config.getResources(); +// got simple 32dpi exposed +// checkValue(res, R.configVarying.simple, "simple stylus keysexposed"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag stylus keysexposed"}); - res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_STYLUS, 0, 0, 0, 0, 0); - checkAllExcept(res, new int[]{ - R.configVarying.simple_xx, - R.configVarying.simple_xx_rYY, - R.configVarying.simple_notouch, - R.configVarying.simple_finger}); - - res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_12KEY, 0, 0, 0, 0); - checkAllExcept(res, new int[]{ - R.configVarying.simple_xx, - R.configVarying.simple_xx_rYY}); - - res = getResources(config, 0, 0, 0, 0, 0, 0, 320, 200); - checkAllExcept(res, new int[]{ - R.configVarying.simple_xx, - R.configVarying.simple_xx_rYY, - R.configVarying.simple_480x320}); - - res = getResources(config, 0, 0, 0, 0, 0, 0, 480, 320); - checkAllExcept(res, new int[]{ - R.configVarying.simple_xx, - R.configVarying.simple_xx_rYY, - R.configVarying.simple_320x200}); + config = new TotalConfig(); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); + config.setProperty(properties.HEIGHT, 63); + config.setProperty(properties.WIDTH, 57); + res = config.getResources(); +// got simple 240dpi +// checkValue(res, R.configVarying.simple, "simple 12key dpad"); +// checkValue(res, R.configVarying.bag, +// R.styleable.TestConfig, new String[]{"bag 12key dpad"}); } } diff --git a/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java b/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java index b812181a84f95..564404460229b 100644 --- a/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java +++ b/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java @@ -49,7 +49,7 @@ public class BrightnessLimit extends Activity implements OnClickListener { ServiceManager.getService("hardware")); if (hardware != null) { try { - hardware.setScreenBacklight(0); + hardware.setBacklights(0); } catch (RemoteException darn) { } diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java index 264fcdde1ada2..a88183cffdca5 100644 --- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java @@ -58,22 +58,6 @@ public class NotificationTestList extends TestActivity } private Test[] mTests = new Test[] { - new Test("Crash") { - public void run() - { - PowerManager.WakeLock wl - = ((PowerManager)NotificationTestList.this.getSystemService("power")) - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "crasher"); - wl.acquire(); - mHandler.postDelayed(new Runnable() { - public void run() { - throw new RuntimeException("Die!"); - } - }, 10000); - - } - }, - new Test("No view") { public void run() { Notification n = new Notification(R.drawable.icon1, "No view", @@ -154,6 +138,60 @@ public class NotificationTestList extends TestActivity } }, + new Test("Blue Lights") { + public void run() + { + Notification n = new Notification(); + n.flags |= Notification.FLAG_SHOW_LIGHTS; + n.ledARGB = 0xff0000ff; + mNM.notify(1, n); + } + }, + + new Test("Red Lights") { + public void run() + { + Notification n = new Notification(); + n.flags |= Notification.FLAG_SHOW_LIGHTS; + n.ledARGB = 0xffff0000; + mNM.notify(1, n); + } + }, + + new Test("Yellow Lights") { + public void run() + { + Notification n = new Notification(); + n.flags |= Notification.FLAG_SHOW_LIGHTS; + n.ledARGB = 0xffffff00; + mNM.notify(1, n); + } + }, + + new Test("Blue Blinking Slow") { + public void run() + { + Notification n = new Notification(); + n.flags |= Notification.FLAG_SHOW_LIGHTS; + n.ledARGB = 0xffffff00; + n.ledOnMS = 1300; + n.ledOffMS = 1300; + mNM.notify(1, n); + } + }, + + new Test("Blue Blinking Fast") { + public void run() + { + Notification n = new Notification(); + n.flags |= Notification.FLAG_SHOW_LIGHTS; + n.ledARGB = 0xffffff00; + n.ledOnMS = 300; + n.ledOffMS = 300; + mNM.notify(1, n); + } + }, + new Test("Default All") { public void run() { @@ -468,6 +506,22 @@ public class NotificationTestList extends TestActivity } }, + new Test("Crash") { + public void run() + { + PowerManager.WakeLock wl + = ((PowerManager)NotificationTestList.this.getSystemService("power")) + .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "crasher"); + wl.acquire(); + mHandler.postDelayed(new Runnable() { + public void run() { + throw new RuntimeException("Die!"); + } + }, 10000); + + } + }, + }; private Notification notificationWithNumbers(int num) { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java index f5da91d1af0b0..48998dbafe46f 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java @@ -690,14 +690,15 @@ public final class BridgeTypedArray extends TypedArray { } String value = mData[index].getValue(); - if (value == null) { - return null; + if (value != null) { + return new CharSequence[] { value }; } - throw new UnsupportedOperationException( - String.format("BridgeTypedArray: UNKNOWN VALUE FOR getTextArray(%d) => %s", //DEBUG - index, value)); + mContext.getLogger().warning(String.format( + String.format("Unknown value for getTextArray(%d) => %s", //DEBUG + index, mData[index].getName()))); + return null; } /**